all repos — WarBot2020 @ ef96ab1d3b1cc609ad2ff1ba7040ccfbbb71dbd1

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 */
  141@SuppressWarnings("unchecked") //added by me to suppress warning
  142public class CommandLine {
  143
  144    /** This is picocli version {@value}. */
  145    public static final String VERSION = "4.0.0-alpha-2-SNAPSHOT";
  146
  147    private final Tracer tracer = new Tracer();
  148    private final CommandSpec commandSpec;
  149    private final Interpreter interpreter;
  150    private final IFactory factory;
  151
  152    /**
  153     * 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.
  154     * <p>The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a {@code @Command}-annotated
  155     * user object with {@code @Option} and {@code @Parameters}-annotated fields, in which case picocli automatically
  156     * constructs a {@code CommandSpec} from this user object.
  157     * </p><p>
  158     * When the {@link #parse(String...)} method is called, the {@link CommandSpec CommandSpec} object will be
  159     * initialized based on command line arguments. If the commandSpec is created from an annotated user object, this
  160     * user object will be initialized based on the command line arguments.</p>
  161     * @param command an annotated user object or a {@code CommandSpec} object to initialize from the command line arguments
  162     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
  163     */
  164    public CommandLine(Object command) {
  165        this(command, new DefaultFactory());
  166    }
  167    /**
  168     * 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.
  169     * <p>The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a {@code @Command}-annotated
  170     * user object with {@code @Option} and {@code @Parameters}-annotated fields, in which case picocli automatically
  171     * constructs a {@code CommandSpec} from this user object.
  172     *  </p><p> If the specified command object is an interface {@code Class} with {@code @Option} and {@code @Parameters}-annotated methods,
  173     * picocli creates a {@link java.lang.reflect.Proxy Proxy} whose methods return the matched command line values.
  174     * If the specified command object is a concrete {@code Class}, picocli delegates to the {@linkplain IFactory factory} to get an instance.
  175     * </p><p>
  176     * When the {@link #parse(String...)} method is called, the {@link CommandSpec CommandSpec} object will be
  177     * initialized based on command line arguments. If the commandSpec is created from an annotated user object, this
  178     * user object will be initialized based on the command line arguments.</p>
  179     * @param command an annotated user object or a {@code CommandSpec} object to initialize from the command line arguments
  180     * @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
  181     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
  182     * @since 2.2 */
  183    public CommandLine(Object command, IFactory factory) {
  184        this.factory = Assert.notNull(factory, "factory");
  185        interpreter = new Interpreter();
  186        commandSpec = CommandSpec.forAnnotatedObject(command, factory);
  187        commandSpec.commandLine(this);
  188        commandSpec.validate();
  189        if (commandSpec.unmatchedArgsBindings().size() > 0) { setUnmatchedArgumentsAllowed(true); }
  190    }
  191
  192    /**
  193     * Returns the {@code CommandSpec} model that this {@code CommandLine} was constructed with.
  194     * @return the {@code CommandSpec} model
  195     * @since 3.0 */
  196    public CommandSpec getCommandSpec() { return commandSpec; }
  197
  198    /**
  199     * Adds the options and positional parameters in the specified mixin to this command.
  200     * <p>The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a user object with
  201     * {@code @Option} and {@code @Parameters}-annotated fields, in which case picocli automatically
  202     * constructs a {@code CommandSpec} from this user object.
  203     * </p>
  204     * @param name the name by which the mixin object may later be retrieved
  205     * @param mixin an annotated user object or a {@link CommandSpec CommandSpec} object whose options and positional parameters to add to this command
  206     * @return this CommandLine object, to allow method chaining
  207     * @since 3.0 */
  208    public CommandLine addMixin(String name, Object mixin) {
  209        getCommandSpec().addMixin(name, CommandSpec.forAnnotatedObject(mixin, factory));
  210        return this;
  211    }
  212
  213    /**
  214     * Returns a map of user objects whose options and positional parameters were added to ("mixed in" with) this command.
  215     * @return a new Map containing the user objects mixed in with this command. If {@code CommandSpec} objects without
  216     *          user objects were programmatically added, use the {@link CommandSpec#mixins() underlying model} directly.
  217     * @since 3.0 */
  218    public Map<String, Object> getMixins() {
  219        Map<String, CommandSpec> mixins = getCommandSpec().mixins();
  220        Map<String, Object> result = new LinkedHashMap<String, Object>();
  221        for (String name : mixins.keySet()) { result.put(name, mixins.get(name).userObject); }
  222        return result;
  223    }
  224
  225    /** Registers a subcommand with the specified name. For example:
  226     * <pre>
  227     * CommandLine commandLine = new CommandLine(new Git())
  228     *         .addSubcommand("status",   new GitStatus())
  229     *         .addSubcommand("commit",   new GitCommit();
  230     *         .addSubcommand("add",      new GitAdd())
  231     *         .addSubcommand("branch",   new GitBranch())
  232     *         .addSubcommand("checkout", new GitCheckout())
  233     *         //...
  234     *         ;
  235     * </pre>
  236     *
  237     * <p>The specified object can be an annotated object or a
  238     * {@code CommandLine} instance with its own nested subcommands. For example:</p>
  239     * <pre>
  240     * CommandLine commandLine = new CommandLine(new MainCommand())
  241     *         .addSubcommand("cmd1",                 new ChildCommand1()) // subcommand
  242     *         .addSubcommand("cmd2",                 new ChildCommand2())
  243     *         .addSubcommand("cmd3", new CommandLine(new ChildCommand3()) // subcommand with nested sub-subcommands
  244     *                 .addSubcommand("cmd3sub1",                 new GrandChild3Command1())
  245     *                 .addSubcommand("cmd3sub2",                 new GrandChild3Command2())
  246     *                 .addSubcommand("cmd3sub3", new CommandLine(new GrandChild3Command3()) // deeper nesting
  247     *                         .addSubcommand("cmd3sub3sub1", new GreatGrandChild3Command3_1())
  248     *                         .addSubcommand("cmd3sub3sub2", new GreatGrandChild3Command3_2())
  249     *                 )
  250     *         );
  251     * </pre>
  252     * <p>The default type converters are available on all subcommands and nested sub-subcommands, but custom type
  253     * converters are registered only with the subcommand hierarchy as it existed when the custom type was registered.
  254     * To ensure a custom type converter is available to all subcommands, register the type converter last, after
  255     * adding subcommands.</p>
  256     * <p>See also the {@link Command#subcommands()} annotation to register subcommands declaratively.</p>
  257     *
  258     * @param name the string to recognize on the command line as a subcommand
  259     * @param command the object to initialize with command line arguments following the subcommand name.
  260     *          This may be a {@code CommandLine} instance with its own (nested) subcommands
  261     * @return this CommandLine object, to allow method chaining
  262     * @see #registerConverter(Class, ITypeConverter)
  263     * @since 0.9.7
  264     * @see Command#subcommands()
  265     */
  266    public CommandLine addSubcommand(String name, Object command) {
  267        return addSubcommand(name, command, new String[0]);
  268    }
  269
  270    /** Registers a subcommand with the specified name and all specified aliases. See also {@link #addSubcommand(String, Object)}.
  271     *
  272     *
  273     * @param name the string to recognize on the command line as a subcommand
  274     * @param command the object to initialize with command line arguments following the subcommand name.
  275     *          This may be a {@code CommandLine} instance with its own (nested) subcommands
  276     * @param aliases zero or more alias names that are also recognized on the command line as this subcommand
  277     * @return this CommandLine object, to allow method chaining
  278     * @since 3.1
  279     * @see #addSubcommand(String, Object)
  280     */
  281    public CommandLine addSubcommand(String name, Object command, String... aliases) {
  282        CommandLine subcommandLine = toCommandLine(command, factory);
  283        subcommandLine.getCommandSpec().aliases.addAll(Arrays.asList(aliases));
  284        getCommandSpec().addSubcommand(name, subcommandLine);
  285        CommandLine.Model.CommandReflection.initParentCommand(subcommandLine.getCommandSpec().userObject(), getCommandSpec().userObject());
  286        return this;
  287    }
  288    /** Returns a map with the subcommands {@linkplain #addSubcommand(String, Object) registered} on this instance.
  289     * @return a map with the registered subcommands
  290     * @since 0.9.7
  291     */
  292    public Map<String, CommandLine> getSubcommands() {
  293        return new LinkedHashMap<String, CommandLine>(getCommandSpec().subcommands());
  294    }
  295    /**
  296     * Returns the command that this is a subcommand of, or {@code null} if this is a top-level command.
  297     * @return the command that this is a subcommand of, or {@code null} if this is a top-level command
  298     * @see #addSubcommand(String, Object)
  299     * @see Command#subcommands()
  300     * @since 0.9.8
  301     */
  302    public CommandLine getParent() {
  303        CommandSpec parent = getCommandSpec().parent();
  304        return parent == null ? null : parent.commandLine();
  305    }
  306
  307    /** Returns the annotated user object that this {@code CommandLine} instance was constructed with.
  308     * @param <T> the type of the variable that the return value is being assigned to
  309     * @return the annotated object that this {@code CommandLine} instance was constructed with
  310     * @since 0.9.7
  311     */
  312    @SuppressWarnings("unchecked")
  313    public <T> T getCommand() {
  314        return (T) getCommandSpec().userObject();
  315    }
  316
  317    /** Returns {@code true} if an option annotated with {@link Option#usageHelp()} was specified on the command line.
  318     * @return whether the parser encountered an option annotated with {@link Option#usageHelp()}.
  319     * @since 0.9.8 */
  320    public boolean isUsageHelpRequested() { return interpreter.parseResultBuilder != null && interpreter.parseResultBuilder.usageHelpRequested; }
  321
  322    /** Returns {@code true} if an option annotated with {@link Option#versionHelp()} was specified on the command line.
  323     * @return whether the parser encountered an option annotated with {@link Option#versionHelp()}.
  324     * @since 0.9.8 */
  325    public boolean isVersionHelpRequested() { return interpreter.parseResultBuilder != null && interpreter.parseResultBuilder.versionHelpRequested; }
  326
  327    /** Returns the {@code IHelpFactory} that is used to construct the usage help message.
  328     * @see #setHelpFactory(IHelpFactory)
  329     * @since 3.9
  330     */
  331    public IHelpFactory getHelpFactory() {
  332        return getCommandSpec().usageMessage().helpFactory();
  333    }
  334
  335    /** Sets a new {@code IHelpFactory} to customize the usage help message.
  336     * @param helpFactory the new help factory. Must be non-{@code null}.
  337     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  338     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  339     * later will have the default setting. To ensure a setting is applied to all
  340     * subcommands, call the setter last, after adding subcommands.</p>
  341     * @return this {@code CommandLine} object, to allow method chaining
  342     * @since 3.9
  343     */
  344    public CommandLine setHelpFactory(IHelpFactory helpFactory) {
  345        getCommandSpec().usageMessage().helpFactory(helpFactory);
  346        for (CommandLine command : getCommandSpec().subcommands().values()) {
  347            command.setHelpFactory(helpFactory);
  348        }
  349        return this;
  350    }
  351
  352    /**
  353     * Returns the section keys in the order that the usage help message should render the sections.
  354     * This ordering may be modified with {@link #setHelpSectionKeys(List) setSectionKeys}. The default keys are (in order):
  355     * <ol>
  356     *   <li>{@link UsageMessageSpec#SECTION_KEY_HEADER_HEADING SECTION_KEY_HEADER_HEADING}</li>
  357     *   <li>{@link UsageMessageSpec#SECTION_KEY_HEADER SECTION_KEY_HEADER}</li>
  358     *   <li>{@link UsageMessageSpec#SECTION_KEY_SYNOPSIS_HEADING SECTION_KEY_SYNOPSIS_HEADING}</li>
  359     *   <li>{@link UsageMessageSpec#SECTION_KEY_SYNOPSIS SECTION_KEY_SYNOPSIS}</li>
  360     *   <li>{@link UsageMessageSpec#SECTION_KEY_DESCRIPTION_HEADING SECTION_KEY_DESCRIPTION_HEADING}</li>
  361     *   <li>{@link UsageMessageSpec#SECTION_KEY_DESCRIPTION SECTION_KEY_DESCRIPTION}</li>
  362     *   <li>{@link UsageMessageSpec#SECTION_KEY_PARAMETER_LIST_HEADING SECTION_KEY_PARAMETER_LIST_HEADING}</li>
  363     *   <li>{@link UsageMessageSpec#SECTION_KEY_PARAMETER_LIST SECTION_KEY_PARAMETER_LIST}</li>
  364     *   <li>{@link UsageMessageSpec#SECTION_KEY_OPTION_LIST_HEADING SECTION_KEY_OPTION_LIST_HEADING}</li>
  365     *   <li>{@link UsageMessageSpec#SECTION_KEY_OPTION_LIST SECTION_KEY_OPTION_LIST}</li>
  366     *   <li>{@link UsageMessageSpec#SECTION_KEY_COMMAND_LIST_HEADING SECTION_KEY_COMMAND_LIST_HEADING}</li>
  367     *   <li>{@link UsageMessageSpec#SECTION_KEY_COMMAND_LIST SECTION_KEY_COMMAND_LIST}</li>
  368     *   <li>{@link UsageMessageSpec#SECTION_KEY_FOOTER_HEADING SECTION_KEY_FOOTER_HEADING}</li>
  369     *   <li>{@link UsageMessageSpec#SECTION_KEY_FOOTER SECTION_KEY_FOOTER}</li>
  370     * </ol>
  371     * @since 3.9
  372     */
  373    public List<String> getHelpSectionKeys() { return getCommandSpec().usageMessage().sectionKeys(); }
  374
  375    /**
  376     * Sets the section keys in the order that the usage help message should render the sections.
  377     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  378     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  379     * later will have the default setting. To ensure a setting is applied to all
  380     * subcommands, call the setter last, after adding subcommands.</p>
  381     * <p>Use {@link UsageMessageSpec#sectionKeys(List)} to customize a command without affecting its subcommands.</p>
  382     * @see #getHelpSectionKeys
  383     * @since 3.9
  384     */
  385    public CommandLine setHelpSectionKeys(List<String> keys) {
  386        getCommandSpec().usageMessage().sectionKeys(keys);
  387        for (CommandLine command : getCommandSpec().subcommands().values()) {
  388            command.setHelpSectionKeys(keys);
  389        }
  390        return this;
  391    }
  392
  393    /**
  394     * Returns the map of section keys and renderers used to construct the usage help message.
  395     * The usage help message can be customized by adding, replacing and removing section renderers from this map.
  396     * Sections can be reordered with {@link #setHelpSectionKeys(List) setSectionKeys}.
  397     * Sections that are either not in this map or not in the list returned by {@link #getHelpSectionKeys() getSectionKeys} are omitted.
  398     * <p>
  399     * NOTE: By modifying the returned {@code Map}, only the usage help message <em>of this command</em> is affected.
  400     * Use {@link #setHelpSectionMap(Map)} to customize the usage help message for this command <em>and all subcommands</em>.
  401     * </p>
  402     * @since 3.9
  403     */
  404    public Map<String, IHelpSectionRenderer> getHelpSectionMap() { return getCommandSpec().usageMessage().sectionMap(); }
  405
  406    /**
  407     * Sets the map of section keys and renderers used to construct the usage help message.
  408     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  409     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  410     * later will have the default setting. To ensure a setting is applied to all
  411     * subcommands, call the setter last, after adding subcommands.</p>
  412     * <p>Use {@link UsageMessageSpec#sectionMap(Map)} to customize a command without affecting its subcommands.</p>
  413     * @see #getHelpSectionMap
  414     * @since 3.9
  415     */
  416    public CommandLine setHelpSectionMap(Map<String, IHelpSectionRenderer> map) {
  417        getCommandSpec().usageMessage().sectionMap(map);
  418        for (CommandLine command : getCommandSpec().subcommands().values()) {
  419            command.setHelpSectionMap(map);
  420        }
  421        return this;
  422    }
  423
  424    /** Returns whether the value of boolean flag options should be "toggled" when the option is matched.
  425     * By default, flags are toggled, so if the value is {@code true} it is set to {@code false}, and when the value is
  426     * {@code false} it is set to {@code true}. If toggling is off, flags are simply set to {@code true}.
  427     * @return {@code true} the value of boolean flag options should be "toggled" when the option is matched, {@code false} otherwise
  428     * @since 3.0
  429     */
  430    public boolean isToggleBooleanFlags() {
  431        return getCommandSpec().parser().toggleBooleanFlags();
  432    }
  433
  434    /** Sets whether the value of boolean flag options should be "toggled" when the option is matched. The default is {@code true}.
  435     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  436     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  437     * later will have the default setting. To ensure a setting is applied to all
  438     * subcommands, call the setter last, after adding subcommands.</p>
  439     * @param newValue the new setting
  440     * @return this {@code CommandLine} object, to allow method chaining
  441     * @since 3.0
  442     */
  443    public CommandLine setToggleBooleanFlags(boolean newValue) {
  444        getCommandSpec().parser().toggleBooleanFlags(newValue);
  445        for (CommandLine command : getCommandSpec().subcommands().values()) {
  446            command.setToggleBooleanFlags(newValue);
  447        }
  448        return this;
  449    }
  450
  451    /** Returns whether options for single-value fields can be specified multiple times on the command line.
  452     * The default is {@code false} and a {@link OverwrittenOptionException} is thrown if this happens.
  453     * When {@code true}, the last specified value is retained.
  454     * @return {@code true} if options for single-value fields can be specified multiple times on the command line, {@code false} otherwise
  455     * @since 0.9.7
  456     */
  457    public boolean isOverwrittenOptionsAllowed() {
  458        return getCommandSpec().parser().overwrittenOptionsAllowed();
  459    }
  460
  461    /** Sets whether options for single-value fields can be specified multiple times on the command line without a {@link OverwrittenOptionException} being thrown.
  462     * The default is {@code false}.
  463     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  464     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  465     * later will have the default setting. To ensure a setting is applied to all
  466     * subcommands, call the setter last, after adding subcommands.</p>
  467     * @param newValue the new setting
  468     * @return this {@code CommandLine} object, to allow method chaining
  469     * @since 0.9.7
  470     */
  471    public CommandLine setOverwrittenOptionsAllowed(boolean newValue) {
  472        getCommandSpec().parser().overwrittenOptionsAllowed(newValue);
  473        for (CommandLine command : getCommandSpec().subcommands().values()) {
  474            command.setOverwrittenOptionsAllowed(newValue);
  475        }
  476        return this;
  477    }
  478
  479    /** Returns whether the parser accepts clustered short options. The default is {@code true}.
  480     * @return {@code true} if short options like {@code -x -v -f SomeFile} can be clustered together like {@code -xvfSomeFile}, {@code false} otherwise
  481     * @since 3.0 */
  482    public boolean isPosixClusteredShortOptionsAllowed() { return getCommandSpec().parser().posixClusteredShortOptionsAllowed(); }
  483
  484    /** Sets whether short options like {@code -x -v -f SomeFile} can be clustered together like {@code -xvfSomeFile}. The default is {@code true}.
  485     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  486     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  487     * later will have the default setting. To ensure a setting is applied to all
  488     * subcommands, call the setter last, after adding subcommands.</p>
  489     * @param newValue the new setting
  490     * @return this {@code CommandLine} object, to allow method chaining
  491     * @since 3.0
  492     */
  493    public CommandLine setPosixClusteredShortOptionsAllowed(boolean newValue) {
  494        getCommandSpec().parser().posixClusteredShortOptionsAllowed(newValue);
  495        for (CommandLine command : getCommandSpec().subcommands().values()) {
  496            command.setPosixClusteredShortOptionsAllowed(newValue);
  497        }
  498        return this;
  499    }
  500
  501    /** Returns whether the parser should ignore case when converting arguments to {@code enum} values. The default is {@code false}.
  502     * @return {@code true} if enum values can be specified that don't match the {@code toString()} value of the enum constant, {@code false} otherwise;
  503     * 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>,
  504     * values {@code MonDaY}, {@code monday} and {@code MONDAY} are all recognized if {@code true}.
  505     * @since 3.4 */
  506    public boolean isCaseInsensitiveEnumValuesAllowed() { return getCommandSpec().parser().caseInsensitiveEnumValuesAllowed(); }
  507
  508    /** Sets whether the parser should ignore case when converting arguments to {@code enum} values. The default is {@code false}.
  509     * 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>,
  510     * values {@code MonDaY}, {@code monday} and {@code MONDAY} are all recognized if {@code true}.
  511     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  512     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  513     * later will have the default setting. To ensure a setting is applied to all
  514     * subcommands, call the setter last, after adding subcommands.</p>
  515     * @param newValue the new setting
  516     * @return this {@code CommandLine} object, to allow method chaining
  517     * @since 3.4
  518     */
  519    public CommandLine setCaseInsensitiveEnumValuesAllowed(boolean newValue) {
  520        getCommandSpec().parser().caseInsensitiveEnumValuesAllowed(newValue);
  521        for (CommandLine command : getCommandSpec().subcommands().values()) {
  522            command.setCaseInsensitiveEnumValuesAllowed(newValue);
  523        }
  524        return this;
  525    }
  526
  527    /** Returns whether the parser should trim quotes from command line arguments before processing them. The default is
  528     * read from the system property "picocli.trimQuotes" and will be {@code true} if the property is present and empty,
  529     * or if its value is "true".
  530     * @return {@code true} if the parser should trim quotes from command line arguments before processing them, {@code false} otherwise;
  531     * @since 3.7 */
  532    public boolean isTrimQuotes() { return getCommandSpec().parser().trimQuotes(); }
  533
  534    /** Sets whether the parser should trim quotes from command line arguments before processing them. The default is
  535     * read from the system property "picocli.trimQuotes" and will be {@code true} if the property is set and empty, or
  536     * if its value is "true".
  537     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  538     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  539     * later will have the default setting. To ensure a setting is applied to all
  540     * subcommands, call the setter last, after adding subcommands.</p>
  541     * <p>Calling this method will cause the "picocli.trimQuotes" property to have no effect.</p>
  542     * @param newValue the new setting
  543     * @return this {@code CommandLine} object, to allow method chaining
  544     * @since 3.7
  545     */
  546    public CommandLine setTrimQuotes(boolean newValue) {
  547        getCommandSpec().parser().trimQuotes(newValue);
  548        for (CommandLine command : getCommandSpec().subcommands().values()) {
  549            command.setTrimQuotes(newValue);
  550        }
  551        return this;
  552    }
  553
  554    /** Returns whether the parser is allowed to split quoted Strings or not. The default is {@code false},
  555     * so quoted strings are treated as a single value that cannot be split.
  556     * @return {@code true} if the parser is allowed to split quoted Strings, {@code false} otherwise;
  557     * @see ArgSpec#splitRegex()
  558     * @since 3.7 */
  559    public boolean isSplitQuotedStrings() { return getCommandSpec().parser().splitQuotedStrings(); }
  560
  561    /** Sets whether the parser is allowed to split quoted Strings. The default is {@code false}.
  562     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  563     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  564     * later will have the default setting. To ensure a setting is applied to all
  565     * subcommands, call the setter last, after adding subcommands.</p>
  566     * @param newValue the new setting
  567     * @return this {@code CommandLine} object, to allow method chaining
  568     * @see ArgSpec#splitRegex()
  569     * @since 3.7
  570     */
  571    public CommandLine setSplitQuotedStrings(boolean newValue) {
  572        getCommandSpec().parser().splitQuotedStrings(newValue);
  573        for (CommandLine command : getCommandSpec().subcommands().values()) {
  574            command.setSplitQuotedStrings(newValue);
  575        }
  576        return this;
  577    }
  578
  579    /** Returns the end-of-options delimiter that signals that the remaining command line arguments should be treated as positional parameters.
  580     * @return the end-of-options delimiter. The default is {@code "--"}.
  581     * @since 3.5 */
  582    public String getEndOfOptionsDelimiter() { return getCommandSpec().parser().endOfOptionsDelimiter(); }
  583
  584    /** Sets the end-of-options delimiter that signals that the remaining command line arguments should be treated as positional parameters.
  585     * @param delimiter the end-of-options delimiter; must not be {@code null}. The default is {@code "--"}.
  586     * @return this {@code CommandLine} object, to allow method chaining
  587     * @since 3.5 */
  588    public CommandLine setEndOfOptionsDelimiter(String delimiter) {
  589        getCommandSpec().parser().endOfOptionsDelimiter(delimiter);
  590        for (CommandLine command : getCommandSpec().subcommands().values()) {
  591            command.setEndOfOptionsDelimiter(delimiter);
  592        }
  593        return this;
  594    }
  595
  596    /** Returns the default value provider for the command, or {@code null} if none has been set.
  597     * @return the default value provider for this command, or {@code null}
  598     * @since 3.6
  599     * @see Command#defaultValueProvider()
  600     * @see CommandSpec#defaultValueProvider()
  601     * @see ArgSpec#defaultValueString()
  602     */
  603    public IDefaultValueProvider getDefaultValueProvider() {
  604        return getCommandSpec().defaultValueProvider();
  605    }
  606
  607    /** Sets a default value provider for the command and sub-commands
  608     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  609     * sub-commands and nested sub-subcommands <em>at the moment this method is called</em>. Sub-commands added
  610     * later will have the default setting. To ensure a setting is applied to all
  611     * sub-commands, call the setter last, after adding sub-commands.</p>
  612     * @param newValue the default value provider to use
  613     * @return this {@code CommandLine} object, to allow method chaining
  614     * @since 3.6
  615     */
  616    public CommandLine setDefaultValueProvider(IDefaultValueProvider newValue) {
  617        getCommandSpec().defaultValueProvider(newValue);
  618        for (CommandLine command : getCommandSpec().subcommands().values()) {
  619            command.setDefaultValueProvider(newValue);
  620        }
  621        return this;
  622    }
  623
  624    /** Returns whether the parser interprets the first positional parameter as "end of options" so the remaining
  625     * arguments are all treated as positional parameters. The default is {@code false}.
  626     * @return {@code true} if all values following the first positional parameter should be treated as positional parameters, {@code false} otherwise
  627     * @since 2.3
  628     */
  629    public boolean isStopAtPositional() {
  630        return getCommandSpec().parser().stopAtPositional();
  631    }
  632
  633    /** Sets whether the parser interprets the first positional parameter as "end of options" so the remaining
  634     * arguments are all treated as positional parameters. The default is {@code false}.
  635     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  636     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  637     * later will have the default setting. To ensure a setting is applied to all
  638     * subcommands, call the setter last, after adding subcommands.</p>
  639     * @param newValue {@code true} if all values following the first positional parameter should be treated as positional parameters, {@code false} otherwise
  640     * @return this {@code CommandLine} object, to allow method chaining
  641     * @since 2.3
  642     */
  643    public CommandLine setStopAtPositional(boolean newValue) {
  644        getCommandSpec().parser().stopAtPositional(newValue);
  645        for (CommandLine command : getCommandSpec().subcommands().values()) {
  646            command.setStopAtPositional(newValue);
  647        }
  648        return this;
  649    }
  650
  651    /** Returns whether the parser should stop interpreting options and positional parameters as soon as it encounters an
  652     * unmatched option. Unmatched options are arguments that look like an option but are not one of the known options, or
  653     * positional arguments for which there is no available slots (the command has no positional parameters or their size is limited).
  654     * The default is {@code false}.
  655     * <p>Setting this flag to {@code true} automatically sets the {@linkplain #isUnmatchedArgumentsAllowed() unmatchedArgumentsAllowed} flag to {@code true} also.</p>
  656     * @return {@code true} when an unmatched option should result in the remaining command line arguments to be added to the
  657     *      {@linkplain #getUnmatchedArguments() unmatchedArguments list}
  658     * @since 2.3
  659     */
  660    public boolean isStopAtUnmatched() {
  661        return getCommandSpec().parser().stopAtUnmatched();
  662    }
  663
  664    /** Sets whether the parser should stop interpreting options and positional parameters as soon as it encounters an
  665     * unmatched option. Unmatched options are arguments that look like an option but are not one of the known options, or
  666     * positional arguments for which there is no available slots (the command has no positional parameters or their size is limited).
  667     * The default is {@code false}.
  668     * <p>Setting this flag to {@code true} automatically sets the {@linkplain #setUnmatchedArgumentsAllowed(boolean) unmatchedArgumentsAllowed} flag to {@code true} also.</p>
  669     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  670     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  671     * later will have the default setting. To ensure a setting is applied to all
  672     * subcommands, call the setter last, after adding subcommands.</p>
  673     * @param newValue {@code true} when an unmatched option should result in the remaining command line arguments to be added to the
  674     *      {@linkplain #getUnmatchedArguments() unmatchedArguments list}
  675     * @return this {@code CommandLine} object, to allow method chaining
  676     * @since 2.3
  677     */
  678    public CommandLine setStopAtUnmatched(boolean newValue) {
  679        getCommandSpec().parser().stopAtUnmatched(newValue);
  680        for (CommandLine command : getCommandSpec().subcommands().values()) {
  681            command.setStopAtUnmatched(newValue);
  682        }
  683        if (newValue) { setUnmatchedArgumentsAllowed(true); }
  684        return this;
  685    }
  686
  687    /** Returns whether arguments on the command line that resemble an option should be treated as positional parameters.
  688     * The default is {@code false} and the parser behaviour depends on {@link #isUnmatchedArgumentsAllowed()}.
  689     * @return {@code true} arguments on the command line that resemble an option should be treated as positional parameters, {@code false} otherwise
  690     * @see #getUnmatchedArguments()
  691     * @since 3.0
  692     */
  693    public boolean isUnmatchedOptionsArePositionalParams() {
  694        return getCommandSpec().parser().unmatchedOptionsArePositionalParams();
  695    }
  696
  697    /** Sets whether arguments on the command line that resemble an option should be treated as positional parameters.
  698     * The default is {@code false}.
  699     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  700     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  701     * later will have the default setting. To ensure a setting is applied to all
  702     * subcommands, call the setter last, after adding subcommands.</p>
  703     * @param newValue the new setting. When {@code true}, arguments on the command line that resemble an option should be treated as positional parameters.
  704     * @return this {@code CommandLine} object, to allow method chaining
  705     * @since 3.0
  706     * @see #getUnmatchedArguments()
  707     * @see #isUnmatchedArgumentsAllowed
  708     */
  709    public CommandLine setUnmatchedOptionsArePositionalParams(boolean newValue) {
  710        getCommandSpec().parser().unmatchedOptionsArePositionalParams(newValue);
  711        for (CommandLine command : getCommandSpec().subcommands().values()) {
  712            command.setUnmatchedOptionsArePositionalParams(newValue);
  713        }
  714        return this;
  715    }
  716
  717    /** Returns whether the end user may specify arguments on the command line that are not matched to any option or parameter fields.
  718     * The default is {@code false} and a {@link UnmatchedArgumentException} is thrown if this happens.
  719     * When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method.
  720     * @return {@code true} if the end use may specify unmatched arguments on the command line, {@code false} otherwise
  721     * @see #getUnmatchedArguments()
  722     * @since 0.9.7
  723     */
  724    public boolean isUnmatchedArgumentsAllowed() {
  725        return getCommandSpec().parser().unmatchedArgumentsAllowed();
  726    }
  727
  728    /** Sets whether the end user may specify unmatched arguments on the command line without a {@link UnmatchedArgumentException} being thrown.
  729     * The default is {@code false}.
  730     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  731     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  732     * later will have the default setting. To ensure a setting is applied to all
  733     * subcommands, call the setter last, after adding subcommands.</p>
  734     * @param newValue the new setting. When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method.
  735     * @return this {@code CommandLine} object, to allow method chaining
  736     * @since 0.9.7
  737     * @see #getUnmatchedArguments()
  738     */
  739    public CommandLine setUnmatchedArgumentsAllowed(boolean newValue) {
  740        getCommandSpec().parser().unmatchedArgumentsAllowed(newValue);
  741        for (CommandLine command : getCommandSpec().subcommands().values()) {
  742            command.setUnmatchedArgumentsAllowed(newValue);
  743        }
  744        return this;
  745    }
  746
  747    /** Returns the list of unmatched command line arguments, if any.
  748     * @return the list of unmatched command line arguments or an empty list
  749     * @see #isUnmatchedArgumentsAllowed()
  750     * @since 0.9.7
  751     */
  752    public List<String> getUnmatchedArguments() {
  753        return interpreter.parseResultBuilder == null ? Collections.<String>emptyList() : UnmatchedArgumentException.stripErrorMessage(interpreter.parseResultBuilder.unmatched);
  754    }
  755
  756    /**
  757     * <p>
  758     * Convenience method that initializes the specified annotated object from the specified command line arguments.
  759     * </p><p>
  760     * This is equivalent to
  761     * </p><pre>
  762     * CommandLine cli = new CommandLine(command);
  763     * cli.parse(args);
  764     * return command;
  765     * </pre>
  766     *
  767     * @param command the object to initialize. This object contains fields annotated with
  768     *          {@code @Option} or {@code @Parameters}.
  769     * @param args the command line arguments to parse
  770     * @param <T> the type of the annotated object
  771     * @return the specified annotated object
  772     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
  773     * @throws ParameterException if the specified command line arguments are invalid
  774     * @since 0.9.7
  775     */
  776    public static <T> T populateCommand(T command, String... args) {
  777        CommandLine cli = toCommandLine(command, new DefaultFactory());
  778        cli.parse(args);
  779        return command;
  780    }
  781
  782    /**
  783     * <p>
  784     * Convenience method that derives the command specification from the specified interface class, and returns an
  785     * instance of the specified interface. The interface is expected to have annotated getter methods. Picocli will
  786     * instantiate the interface and the getter methods will return the option and positional parameter values matched on the command line.
  787     * </p><p>
  788     * This is equivalent to
  789     * </p><pre>
  790     * CommandLine cli = new CommandLine(spec);
  791     * cli.parse(args);
  792     * return cli.getCommand();
  793     * </pre>
  794     *
  795     * @param spec the interface that defines the command specification. This object contains getter methods annotated with
  796     *          {@code @Option} or {@code @Parameters}.
  797     * @param args the command line arguments to parse
  798     * @param <T> the type of the annotated object
  799     * @return an instance of the specified annotated interface
  800     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
  801     * @throws ParameterException if the specified command line arguments are invalid
  802     * @since 3.1
  803     */
  804    public static <T> T populateSpec(Class<T> spec, String... args) {
  805        CommandLine cli = toCommandLine(spec, new DefaultFactory());
  806        cli.parse(args);
  807        return cli.getCommand();
  808    }
  809
  810    /** Parses the specified command line arguments and returns a list of {@code CommandLine} objects representing the
  811     * top-level command and any subcommands (if any) that were recognized and initialized during the parsing process.
  812     * <p>
  813     * If parsing succeeds, the first element in the returned list is always {@code this CommandLine} object. The
  814     * returned list may contain more elements if subcommands were {@linkplain #addSubcommand(String, Object) registered}
  815     * and these subcommands were initialized by matching command line arguments. If parsing fails, a
  816     * {@link ParameterException} is thrown.
  817     * </p>
  818     *
  819     * @param args the command line arguments to parse
  820     * @return a list with the top-level command and any subcommands initialized by this method
  821     * @throws ParameterException if the specified command line arguments are invalid; use
  822     *      {@link ParameterException#getCommandLine()} to get the command or subcommand whose user input was invalid
  823     */
  824    public List<CommandLine> parse(String... args) {
  825        return interpreter.parse(args);
  826    }
  827    /** Parses the specified command line arguments and returns a list of {@code ParseResult} with the options, positional
  828     * parameters, and subcommands (if any) that were recognized and initialized during the parsing process.
  829     * <p>If parsing fails, a {@link ParameterException} is thrown.</p>
  830     *
  831     * @param args the command line arguments to parse
  832     * @return a list with the top-level command and any subcommands initialized by this method
  833     * @throws ParameterException if the specified command line arguments are invalid; use
  834     *      {@link ParameterException#getCommandLine()} to get the command or subcommand whose user input was invalid
  835     */
  836    public ParseResult parseArgs(String... args) {
  837        interpreter.parse(args);
  838        return getParseResult();
  839    }
  840    public ParseResult getParseResult() { return interpreter.parseResultBuilder == null ? null : interpreter.parseResultBuilder.build(); }
  841    /**
  842     * Represents a function that can process a List of {@code CommandLine} objects resulting from successfully
  843     * {@linkplain #parse(String...) parsing} the command line arguments. This is a
  844     * <a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">functional interface</a>
  845     * whose functional method is {@link #handleParseResult(List, PrintStream, CommandLine.Help.Ansi)}.
  846     * <p>
  847     * Implementations of this functions can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandler}
  848     * methods to take some next step after the command line was successfully parsed.
  849     * </p>
  850     * @see RunFirst
  851     * @see RunLast
  852     * @see RunAll
  853     * @deprecated Use {@link IParseResultHandler2} instead.
  854     * @since 2.0 */
  855    @Deprecated public static interface IParseResultHandler {
  856        /** Processes a List of {@code CommandLine} objects resulting from successfully
  857         * {@linkplain #parse(String...) parsing} the command line arguments and optionally returns a list of results.
  858         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
  859         * @param out the {@code PrintStream} to print help to if requested
  860         * @param ansi for printing help messages using ANSI styles and colors
  861         * @return a list of results, or an empty list if there are no results
  862         * @throws ParameterException if a help command was invoked for an unknown subcommand. Any {@code ParameterExceptions}
  863         *      thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler}
  864         * @throws ExecutionException if a problem occurred while processing the parse results; use
  865         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
  866         */
  867        List<Object> handleParseResult(List<CommandLine> parsedCommands, PrintStream out, Help.Ansi ansi) throws ExecutionException;
  868    }
  869
  870    /**
  871     * Represents a function that can process the {@code ParseResult} object resulting from successfully
  872     * {@linkplain #parseArgs(String...) parsing} the command line arguments. This is a
  873     * <a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">functional interface</a>
  874     * whose functional method is {@link IParseResultHandler2#handleParseResult(CommandLine.ParseResult)}.
  875     * <p>
  876     * Implementations of this function can be passed to the {@link #parseWithHandlers(IParseResultHandler2,  IExceptionHandler2, String...) CommandLine::parseWithHandlers}
  877     * methods to take some next step after the command line was successfully parsed.
  878     * </p><p>
  879     * This interface replaces the {@link IParseResultHandler} interface; it takes the parse result as a {@code ParseResult}
  880     * object instead of a List of {@code CommandLine} objects, and it has the freedom to select the {@link Help.Ansi} style
  881     * to use and what {@code PrintStreams} to print to.
  882     * </p>
  883     * @param <R> the return type of this handler
  884     * @see RunFirst
  885     * @see RunLast
  886     * @see RunAll
  887     * @since 3.0 */
  888    public static interface IParseResultHandler2<R> {
  889        /** Processes the {@code ParseResult} object resulting from successfully
  890         * {@linkplain CommandLine#parseArgs(String...) parsing} the command line arguments and returns a return value.
  891         * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
  892         * @throws ParameterException if a help command was invoked for an unknown subcommand. Any {@code ParameterExceptions}
  893         *      thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler2}
  894         * @throws ExecutionException if a problem occurred while processing the parse results; use
  895         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
  896         */
  897        R handleParseResult(ParseResult parseResult) throws ExecutionException;
  898    }
  899    /**
  900     * Represents a function that can handle a {@code ParameterException} that occurred while
  901     * {@linkplain #parse(String...) parsing} the command line arguments. This is a
  902     * <a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">functional interface</a>
  903     * whose functional method is {@link #handleException(CommandLine.ParameterException, PrintStream, CommandLine.Help.Ansi, String...)}.
  904     * <p>
  905     * Implementations of this function can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandlers}
  906     * methods to handle situations when the command line could not be parsed.
  907     * </p>
  908     * @deprecated Use {@link IExceptionHandler2} instead.
  909     * @see DefaultExceptionHandler
  910     * @since 2.0 */
  911    @Deprecated public static interface IExceptionHandler {
  912        /** Handles a {@code ParameterException} that occurred while {@linkplain #parse(String...) parsing} the command
  913         * line arguments and optionally returns a list of results.
  914         * @param ex the ParameterException describing the problem that occurred while parsing the command line arguments,
  915         *           and the CommandLine representing the command or subcommand whose input was invalid
  916         * @param out the {@code PrintStream} to print help to if requested
  917         * @param ansi for printing help messages using ANSI styles and colors
  918         * @param args the command line arguments that could not be parsed
  919         * @return a list of results, or an empty list if there are no results
  920         */
  921        List<Object> handleException(ParameterException ex, PrintStream out, Help.Ansi ansi, String... args);
  922    }
  923    /**
  924     * Classes implementing this interface know how to handle {@code ParameterExceptions} (usually from invalid user input)
  925     * and {@code ExecutionExceptions} that occurred while executing the {@code Runnable} or {@code Callable} command.
  926     * <p>
  927     * Implementations of this interface can be passed to the
  928     * {@link #parseWithHandlers(IParseResultHandler2,  IExceptionHandler2, String...) CommandLine::parseWithHandlers} method.
  929     * </p><p>
  930     * This interface replaces the {@link IParseResultHandler} interface.
  931     * </p>
  932     * @param <R> the return type of this handler
  933     * @see DefaultExceptionHandler
  934     * @since 3.0 */
  935    public static interface IExceptionHandler2<R> {
  936        /** Handles a {@code ParameterException} that occurred while {@linkplain #parseArgs(String...) parsing} the command
  937         * line arguments and optionally returns a list of results.
  938         * @param ex the ParameterException describing the problem that occurred while parsing the command line arguments,
  939         *           and the CommandLine representing the command or subcommand whose input was invalid
  940         * @param args the command line arguments that could not be parsed
  941         * @return an object resulting from handling the exception
  942         */
  943        R handleParseException(ParameterException ex, String[] args);
  944        /** Handles a {@code ExecutionException} that occurred while executing the {@code Runnable} or
  945         * {@code Callable} command and optionally returns a list of results.
  946         * @param ex the ExecutionException describing the problem that occurred while executing the {@code Runnable} or
  947         *          {@code Callable} command, and the CommandLine representing the command or subcommand that was being executed
  948         * @param parseResult the result of parsing the command line arguments
  949         * @return an object resulting from handling the exception
  950         */
  951        R handleExecutionException(ExecutionException ex, ParseResult parseResult);
  952    }
  953
  954    /** Abstract superclass for {@link IParseResultHandler2} and {@link IExceptionHandler2} implementations.
  955     * <p>Note that {@code AbstractHandler} is a generic type. This, along with the abstract {@code self} method,
  956     * allows method chaining to work properly in subclasses, without the need for casts. An example subclass can look like this:</p>
  957     * <pre>{@code
  958     * class MyResultHandler extends AbstractHandler<MyReturnType, MyResultHandler> implements IParseResultHandler2<MyReturnType> {
  959     *
  960     *     public MyReturnType handleParseResult(ParseResult parseResult) { ... }
  961     *
  962     *     protected MyResultHandler self() { return this; }
  963     * }
  964     * }</pre>
  965     * @param <R> the return type of this handler
  966     * @param <T> The type of the handler subclass; for fluent API method chaining
  967     * @since 3.0 */
  968    public static abstract class AbstractHandler<R, T extends AbstractHandler<R, T>> {
  969        private Help.Ansi ansi = Help.Ansi.AUTO;
  970        private Integer exitCode;
  971        private PrintStream out = System.out;
  972        private PrintStream err = System.err;
  973
  974        /** Returns the stream to print command output to. Defaults to {@code System.out}, unless {@link #useOut(PrintStream)}
  975         * was called with a different stream.
  976         * <p>{@code IParseResultHandler2} implementations should use this stream.
  977         * By <a href="http://www.gnu.org/prep/standards/html_node/_002d_002dhelp.html">convention</a>, when the user requests
  978         * 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> */
  979        public PrintStream out()     { return out; }
  980        /** Returns the stream to print diagnostic messages to. Defaults to {@code System.err}, unless {@link #useErr(PrintStream)}
  981         * was called with a different stream. <p>{@code IExceptionHandler2} implementations should use this stream to print error
  982         * messages (which may include a usage help message) when an unexpected error occurs.</p> */
  983        public PrintStream err()     { return err; }
  984        /** Returns the ANSI style to use. Defaults to {@code Help.Ansi.AUTO}, unless {@link #useAnsi(CommandLine.Help.Ansi)} was called with a different setting. */
  985        public Help.Ansi ansi()      { return ansi; }
  986        /** Returns the exit code to use as the termination status, or {@code null} (the default) if the handler should
  987         * not call {@link System#exit(int)} after processing completes.
  988         * @see #andExit(int) */
  989        public Integer exitCode()    { return exitCode; }
  990        /** Returns {@code true} if an exit code was set with {@link #andExit(int)}, or {@code false} (the default) if
  991         * the handler should not call {@link System#exit(int)} after processing completes. */
  992        public boolean hasExitCode() { return exitCode != null; }
  993
  994        /** Convenience method for subclasses that returns the specified result object if no exit code was set,
  995         * or otherwise, if an exit code {@linkplain #andExit(int) was set}, calls {@code System.exit} with the configured
  996         * exit code to terminate the currently running Java virtual machine. */
  997        protected R returnResultOrExit(R result) {
  998            if (hasExitCode()) { exit(exitCode()); }
  999            return result;
 1000        }
 1001
 1002        /** Convenience method for subclasses that throws the specified ExecutionException if no exit code was set,
 1003         * or otherwise, if an exit code {@linkplain #andExit(int) was set}, prints the stacktrace of the specified exception
 1004         * to the diagnostic error stream and calls {@code System.exit} with the configured
 1005         * exit code to terminate the currently running Java virtual machine. */
 1006        protected R throwOrExit(ExecutionException ex) {
 1007            if (hasExitCode()) {
 1008                ex.printStackTrace(this.err());
 1009                exit(exitCode());
 1010            }
 1011            throw ex;
 1012        }
 1013        /** Calls {@code System.exit(int)} with the specified exit code. */
 1014        protected void exit(int exitCode) { System.exit(exitCode); }
 1015
 1016        /** Returns {@code this} to allow method chaining when calling the setters for a fluent API. */
 1017        protected abstract T self();
 1018
 1019        /** Sets the stream to print command output to. For use by {@code IParseResultHandler2} implementations.
 1020         * @see #out() */
 1021        public T useOut(PrintStream out)   { this.out =  Assert.notNull(out, "out");   return self(); }
 1022        /** Sets the stream to print diagnostic messages to. For use by {@code IExceptionHandler2} implementations.
 1023         * @see #err()*/
 1024        public T useErr(PrintStream err)   { this.err =  Assert.notNull(err, "err");   return self(); }
 1025        /** Sets the ANSI style to use.
 1026         * @see #ansi() */
 1027        public T useAnsi(Help.Ansi ansi)   { this.ansi = Assert.notNull(ansi, "ansi"); return self(); }
 1028        /** Indicates that the handler should call {@link System#exit(int)} after processing completes and sets the exit code to use as the termination status. */
 1029        public T andExit(int exitCode)     { this.exitCode = exitCode; return self(); }
 1030    }
 1031
 1032    /**
 1033     * Default exception handler that handles invalid user input by printing the exception message, followed by the usage
 1034     * message for the command or subcommand whose input was invalid.
 1035     * <p>{@code ParameterExceptions} (invalid user input) is handled like this:</p>
 1036     * <pre>
 1037     *     err().println(paramException.getMessage());
 1038     *     paramException.getCommandLine().usage(err(), ansi());
 1039     *     if (hasExitCode()) System.exit(exitCode()); else return returnValue;
 1040     * </pre>
 1041     * <p>{@code ExecutionExceptions} that occurred while executing the {@code Runnable} or {@code Callable} command are simply rethrown and not handled.</p>
 1042     * @since 2.0 */
 1043    @SuppressWarnings("deprecation")
 1044    public static class DefaultExceptionHandler<R> extends AbstractHandler<R, DefaultExceptionHandler<R>> implements IExceptionHandler, IExceptionHandler2<R> {
 1045        public List<Object> handleException(ParameterException ex, PrintStream out, Help.Ansi ansi, String... args) {
 1046            internalHandleParseException(ex, out, ansi, args); return Collections.<Object>emptyList(); }
 1047
 1048        /** Prints the message of the specified exception, followed by the usage message for the command or subcommand
 1049         * whose input was invalid, to the stream returned by {@link #err()}.
 1050         * @param ex the ParameterException describing the problem that occurred while parsing the command line arguments,
 1051         *           and the CommandLine representing the command or subcommand whose input was invalid
 1052         * @param args the command line arguments that could not be parsed
 1053         * @return the empty list
 1054         * @since 3.0 */
 1055        public R handleParseException(ParameterException ex, String[] args) {
 1056            internalHandleParseException(ex, err(), ansi(), args); return returnResultOrExit(null); }
 1057
 1058        private void internalHandleParseException(ParameterException ex, PrintStream out, Help.Ansi ansi, String[] args) {
 1059            out.println(ex.getMessage());
 1060            if (!UnmatchedArgumentException.printSuggestions(ex, out)) {
 1061                ex.getCommandLine().usage(out, ansi);
 1062            }
 1063        }
 1064        /** This implementation always simply rethrows the specified exception.
 1065         * @param ex the ExecutionException describing the problem that occurred while executing the {@code Runnable} or {@code Callable} command
 1066         * @param parseResult the result of parsing the command line arguments
 1067         * @return nothing: this method always rethrows the specified exception
 1068         * @throws ExecutionException always rethrows the specified exception
 1069         * @since 3.0 */
 1070        public R handleExecutionException(ExecutionException ex, ParseResult parseResult) { return throwOrExit(ex); }
 1071
 1072        @Override protected DefaultExceptionHandler<R> self() { return this; }
 1073    }
 1074    /** Convenience method that returns {@code new DefaultExceptionHandler<List<Object>>()}. */
 1075    public static DefaultExceptionHandler<List<Object>> defaultExceptionHandler() { return new DefaultExceptionHandler<List<Object>>(); }
 1076
 1077    /** @deprecated use {@link #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)} instead
 1078     * @since 2.0 */
 1079    @Deprecated public static boolean printHelpIfRequested(List<CommandLine> parsedCommands, PrintStream out, Help.Ansi ansi) {
 1080        return printHelpIfRequested(parsedCommands, out, out, ansi);
 1081    }
 1082
 1083    /** Delegates to {@link #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)} with
 1084     * {@code parseResult.asCommandLineList(), System.out, System.err, Help.Ansi.AUTO}.
 1085     * @since 3.0 */
 1086    public static boolean printHelpIfRequested(ParseResult parseResult) {
 1087        return printHelpIfRequested(parseResult.asCommandLineList(), System.out, System.err, Help.Ansi.AUTO);
 1088    }
 1089    /**
 1090     * Helper method that may be useful when processing the list of {@code CommandLine} objects that result from successfully
 1091     * {@linkplain #parse(String...) parsing} command line arguments. This method prints out
 1092     * {@linkplain #usage(PrintStream, Help.Ansi) usage help} if {@linkplain #isUsageHelpRequested() requested}
 1093     * or {@linkplain #printVersionHelp(PrintStream, Help.Ansi) version help} if {@linkplain #isVersionHelpRequested() requested}
 1094     * and returns {@code true}. If the command is a {@link Command#helpCommand()} and {@code runnable} or {@code callable},
 1095     * that command is executed and this method returns {@code true}.
 1096     * Otherwise, if none of the specified {@code CommandLine} objects have help requested,
 1097     * this method returns {@code false}.<p>
 1098     * Note that this method <em>only</em> looks at the {@link Option#usageHelp() usageHelp} and
 1099     * {@link Option#versionHelp() versionHelp} attributes. The {@link Option#help() help} attribute is ignored.
 1100     * </p><p><b>Implementation note:</b></p><p>
 1101     * When an error occurs while processing the help request, it is recommended custom Help commands throw a
 1102     * {@link ParameterException} with a reference to the parent command. This will print the error message and the
 1103     * usage for the parent command, and will use the exit code of the exception handler if one was set.
 1104     * </p>
 1105     * @param parsedCommands the list of {@code CommandLine} objects to check if help was requested
 1106     * @param out the {@code PrintStream} to print help to if requested
 1107     * @param err the error string to print diagnostic messages to, in addition to the output from the exception handler
 1108     * @param ansi for printing help messages using ANSI styles and colors
 1109     * @return {@code true} if help was printed, {@code false} otherwise
 1110     * @see IHelpCommandInitializable
 1111     * @since 3.0 */
 1112    public static boolean printHelpIfRequested(List<CommandLine> parsedCommands, PrintStream out, PrintStream err, Help.Ansi ansi) {
 1113        return printHelpIfRequested(parsedCommands, out, err, Help.defaultColorScheme(ansi));
 1114    }
 1115    /**
 1116     * Helper method that may be useful when processing the list of {@code CommandLine} objects that result from successfully
 1117     * {@linkplain #parse(String...) parsing} command line arguments. This method prints out
 1118     * {@linkplain #usage(PrintStream, Help.ColorScheme) usage help} if {@linkplain #isUsageHelpRequested() requested}
 1119     * or {@linkplain #printVersionHelp(PrintStream, Help.Ansi) version help} if {@linkplain #isVersionHelpRequested() requested}
 1120     * and returns {@code true}. If the command is a {@link Command#helpCommand()} and {@code runnable} or {@code callable},
 1121     * that command is executed and this method returns {@code true}.
 1122     * Otherwise, if none of the specified {@code CommandLine} objects have help requested,
 1123     * this method returns {@code false}.<p>
 1124     * Note that this method <em>only</em> looks at the {@link Option#usageHelp() usageHelp} and
 1125     * {@link Option#versionHelp() versionHelp} attributes. The {@link Option#help() help} attribute is ignored.
 1126     * </p><p><b>Implementation note:</b></p><p>
 1127     * When an error occurs while processing the help request, it is recommended custom Help commands throw a
 1128     * {@link ParameterException} with a reference to the parent command. This will print the error message and the
 1129     * usage for the parent command, and will use the exit code of the exception handler if one was set.
 1130     * </p>
 1131     * @param parsedCommands the list of {@code CommandLine} objects to check if help was requested
 1132     * @param out the {@code PrintStream} to print help to if requested
 1133     * @param err the error string to print diagnostic messages to, in addition to the output from the exception handler
 1134     * @param colorScheme for printing help messages using ANSI styles and colors
 1135     * @return {@code true} if help was printed, {@code false} otherwise
 1136     * @see IHelpCommandInitializable
 1137     * @since 3.6 */
 1138    public static boolean printHelpIfRequested(List<CommandLine> parsedCommands, PrintStream out, PrintStream err, Help.ColorScheme colorScheme) {
 1139        for (int i = 0; i < parsedCommands.size(); i++) {
 1140            CommandLine parsed = parsedCommands.get(i);
 1141            if (parsed.isUsageHelpRequested()) {
 1142                parsed.usage(out, colorScheme);
 1143                return true;
 1144            } else if (parsed.isVersionHelpRequested()) {
 1145                parsed.printVersionHelp(out, colorScheme.ansi);
 1146                return true;
 1147            } else if (parsed.getCommandSpec().helpCommand()) {
 1148                if (parsed.getCommand() instanceof IHelpCommandInitializable) {
 1149                    ((IHelpCommandInitializable) parsed.getCommand()).init(parsed, colorScheme.ansi, out, err);
 1150                }
 1151                execute(parsed, new ArrayList<Object>());
 1152                return true;
 1153            }
 1154        }
 1155        return false;
 1156    }
 1157    private static List<Object> execute(CommandLine parsed, List<Object> executionResult) {
 1158        Object command = parsed.getCommand();
 1159        if (command instanceof Runnable) {
 1160            try {
 1161                ((Runnable) command).run();
 1162                executionResult.add(null); // for compatibility with picocli 2.x
 1163                return executionResult;
 1164            } catch (ParameterException ex) {
 1165                throw ex;
 1166            } catch (ExecutionException ex) {
 1167                throw ex;
 1168            } catch (Exception ex) {
 1169                throw new ExecutionException(parsed, "Error while running command (" + command + "): " + ex, ex);
 1170            }
 1171        } else if (command instanceof Callable) {
 1172            try {
 1173                @SuppressWarnings("unchecked") Callable<Object> callable = (Callable<Object>) command;
 1174                executionResult.add(callable.call());
 1175                return executionResult;
 1176            } catch (ParameterException ex) {
 1177                throw ex;
 1178            } catch (ExecutionException ex) {
 1179                throw ex;
 1180            } catch (Exception ex) {
 1181                throw new ExecutionException(parsed, "Error while calling command (" + command + "): " + ex, ex);
 1182            }
 1183        } else if (command instanceof Method) {
 1184            try {
 1185                if (Modifier.isStatic(((Method) command).getModifiers())) {
 1186                    // invoke static method
 1187                    executionResult.add(((Method) command).invoke(null, parsed.getCommandSpec().argValues()));
 1188                    return executionResult;
 1189                } else if (parsed.getCommandSpec().parent() != null) {
 1190                    executionResult.add(((Method) command).invoke(parsed.getCommandSpec().parent().userObject(), parsed.getCommandSpec().argValues()));
 1191                    return executionResult;
 1192                } else {
 1193                    for (Constructor<?> constructor : ((Method) command).getDeclaringClass().getDeclaredConstructors()) {
 1194                        if (constructor.getParameterTypes().length == 0) {
 1195                            executionResult.add(((Method) command).invoke(constructor.newInstance(), parsed.getCommandSpec().argValues()));
 1196                            return executionResult;
 1197                        }
 1198                    }
 1199                    throw new UnsupportedOperationException("Invoking non-static method without default constructor not implemented");
 1200                }
 1201            } catch (InvocationTargetException ex) {
 1202                Throwable t = ex.getTargetException();
 1203                if (t instanceof ParameterException) {
 1204                    throw (ParameterException) t;
 1205                } else if (t instanceof ExecutionException) {
 1206                    throw (ExecutionException) t;
 1207                } else {
 1208                    throw new ExecutionException(parsed, "Error while calling command (" + command + "): " + t, t);
 1209                }
 1210            } catch (Exception ex) {
 1211                throw new ExecutionException(parsed, "Unhandled error while calling command (" + command + "): " + ex, ex);
 1212            }
 1213        }
 1214        throw new ExecutionException(parsed, "Parsed command (" + command + ") is not Method, Runnable or Callable");
 1215    }
 1216    /** Command line parse result handler that returns a value. This handler prints help if requested, and otherwise calls
 1217     * {@link #handle(CommandLine.ParseResult)} with the parse result. Facilitates implementation of the {@link IParseResultHandler2} interface.
 1218     * <p>Note that {@code AbstractParseResultHandler} is a generic type. This, along with the abstract {@code self} method,
 1219     * allows method chaining to work properly in subclasses, without the need for casts. An example subclass can look like this:</p>
 1220     * <pre>{@code
 1221     * class MyResultHandler extends AbstractParseResultHandler<MyReturnType> {
 1222     *
 1223     *     protected MyReturnType handle(ParseResult parseResult) throws ExecutionException { ... }
 1224     *
 1225     *     protected MyResultHandler self() { return this; }
 1226     * }
 1227     * }</pre>
 1228     * @since 3.0 */
 1229    public abstract static class AbstractParseResultHandler<R> extends AbstractHandler<R, AbstractParseResultHandler<R>> implements IParseResultHandler2<R> {
 1230        /** Prints help if requested, and otherwise calls {@link #handle(CommandLine.ParseResult)}.
 1231         * Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}.
 1232         *
 1233         * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
 1234         * @return the result of {@link #handle(ParseResult) processing parse results}
 1235         * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions}
 1236         *      thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler2}
 1237         * @throws ExecutionException if a problem occurred while processing the parse results; client code can use
 1238         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1239         */
 1240        public R handleParseResult(ParseResult parseResult) throws ExecutionException {
 1241            if (printHelpIfRequested(parseResult.asCommandLineList(), out(), err(), ansi())) {
 1242                return returnResultOrExit(null);
 1243            }
 1244            return returnResultOrExit(handle(parseResult));
 1245        }
 1246
 1247        /** Processes the specified {@code ParseResult} and returns the result as a list of objects.
 1248         * Implementations are responsible for catching any exceptions thrown in the {@code handle} method, and
 1249         * rethrowing an {@code ExecutionException} that details the problem and captures the offending {@code CommandLine} object.
 1250         *
 1251         * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
 1252         * @return the result of processing parse results
 1253         * @throws ExecutionException if a problem occurred while processing the parse results; client code can use
 1254         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1255         */
 1256        protected abstract R handle(ParseResult parseResult) throws ExecutionException;
 1257    }
 1258    /**
 1259     * Command line parse result handler that prints help if requested, and otherwise executes the top-level
 1260     * {@code Runnable} or {@code Callable} command.
 1261     * For use in the {@link #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) parseWithHandler} methods.
 1262     * @since 2.0 */
 1263    public static class RunFirst extends AbstractParseResultHandler<List<Object>> implements IParseResultHandler {
 1264        /** Prints help if requested, and otherwise executes the top-level {@code Runnable} or {@code Callable} command.
 1265         * Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}.
 1266         * If the top-level command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
 1267         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
 1268         *
 1269         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
 1270         * @param out the {@code PrintStream} to print help to if requested
 1271         * @param ansi for printing help messages using ANSI styles and colors
 1272         * @return an empty list if help was requested, or a list containing a single element: the result of calling the
 1273         *      {@code Callable}, or a {@code null} element if the top-level command was a {@code Runnable}
 1274         * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions}
 1275         *      thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler}
 1276         * @throws ExecutionException if a problem occurred while processing the parse results; use
 1277         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1278         */
 1279        public List<Object> handleParseResult(List<CommandLine> parsedCommands, PrintStream out, Help.Ansi ansi) {
 1280            if (printHelpIfRequested(parsedCommands, out, err(), ansi)) { return returnResultOrExit(Collections.emptyList()); }
 1281            return returnResultOrExit(execute(parsedCommands.get(0), new ArrayList<Object>()));
 1282        }
 1283        /** Executes the top-level {@code Runnable} or {@code Callable} subcommand.
 1284         * If the top-level command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
 1285         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
 1286         *
 1287         * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
 1288         * @return an empty list if help was requested, or a list containing a single element: the result of calling the
 1289         *      {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable}
 1290         * @throws ExecutionException if a problem occurred while processing the parse results; use
 1291         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1292         * @since 3.0 */
 1293        protected List<Object> handle(ParseResult parseResult) throws ExecutionException {
 1294            return execute(parseResult.commandSpec().commandLine(), new ArrayList<Object>()); // first
 1295        }
 1296        @Override protected RunFirst self() { return this; }
 1297    }
 1298    /**
 1299     * Command line parse result handler that prints help if requested, and otherwise executes the most specific
 1300     * {@code Runnable} or {@code Callable} subcommand.
 1301     * For use in the {@link #parseWithHandlers(IParseResultHandler2,  IExceptionHandler2, String...) parseWithHandler} methods.
 1302     * <p>
 1303     * Something like this:</p>
 1304     * <pre>{@code
 1305     *     // RunLast implementation: print help if requested, otherwise execute the most specific subcommand
 1306     *     List<CommandLine> parsedCommands = parseResult.asCommandLineList();
 1307     *     if (CommandLine.printHelpIfRequested(parsedCommands, out(), err(), ansi())) {
 1308     *         return emptyList();
 1309     *     }
 1310     *     CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
 1311     *     Object command = last.getCommand();
 1312     *     Object result = null;
 1313     *     if (command instanceof Runnable) {
 1314     *         try {
 1315     *             ((Runnable) command).run();
 1316     *         } catch (Exception ex) {
 1317     *             throw new ExecutionException(last, "Error in runnable " + command, ex);
 1318     *         }
 1319     *     } else if (command instanceof Callable) {
 1320     *         try {
 1321     *             result = ((Callable) command).call();
 1322     *         } catch (Exception ex) {
 1323     *             throw new ExecutionException(last, "Error in callable " + command, ex);
 1324     *         }
 1325     *     } else {
 1326     *         throw new ExecutionException(last, "Parsed command (" + command + ") is not Runnable or Callable");
 1327     *     }
 1328     *     if (hasExitCode()) { System.exit(exitCode()); }
 1329     *     return Arrays.asList(result);
 1330     * }</pre>
 1331     * <p>
 1332     * From picocli v2.0, {@code RunLast} is used to implement the {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run}
 1333     * and {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call} convenience methods.
 1334     * </p>
 1335     * @since 2.0 */
 1336    public static class RunLast extends AbstractParseResultHandler<List<Object>> implements IParseResultHandler {
 1337        /** Prints help if requested, and otherwise executes the most specific {@code Runnable} or {@code Callable} subcommand.
 1338         * Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}.
 1339         * If the last (sub)command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
 1340         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
 1341         *
 1342         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
 1343         * @param out the {@code PrintStream} to print help to if requested
 1344         * @param ansi for printing help messages using ANSI styles and colors
 1345         * @return an empty list if help was requested, or a list containing a single element: the result of calling the
 1346         *      {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable}
 1347         * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions}
 1348         *      thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler}
 1349         * @throws ExecutionException if a problem occurred while processing the parse results; use
 1350         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1351         */
 1352        public List<Object> handleParseResult(List<CommandLine> parsedCommands, PrintStream out, Help.Ansi ansi) {
 1353            if (printHelpIfRequested(parsedCommands, out, err(), ansi)) { return returnResultOrExit(Collections.emptyList()); }
 1354            return returnResultOrExit(execute(parsedCommands.get(parsedCommands.size() - 1), new ArrayList<Object>()));
 1355        }
 1356        /** Executes the most specific {@code Runnable} or {@code Callable} subcommand.
 1357         * If the last (sub)command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
 1358         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
 1359         *
 1360         * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
 1361         * @return an empty list if help was requested, or a list containing a single element: the result of calling the
 1362         *      {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable}
 1363         * @throws ExecutionException if a problem occurred while processing the parse results; use
 1364         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1365         * @since 3.0 */
 1366        protected List<Object> handle(ParseResult parseResult) throws ExecutionException {
 1367            List<CommandLine> parsedCommands = parseResult.asCommandLineList();
 1368            return execute(parsedCommands.get(parsedCommands.size() - 1), new ArrayList<Object>());
 1369        }
 1370        @Override protected RunLast self() { return this; }
 1371    }
 1372    /**
 1373     * Command line parse result handler that prints help if requested, and otherwise executes the top-level command and
 1374     * all subcommands as {@code Runnable} or {@code Callable}.
 1375     * For use in the {@link #parseWithHandlers(IParseResultHandler2,  IExceptionHandler2, String...) parseWithHandler} methods.
 1376     * @since 2.0 */
 1377    public static class RunAll extends AbstractParseResultHandler<List<Object>> implements IParseResultHandler {
 1378        /** Prints help if requested, and otherwise executes the top-level command and all subcommands as {@code Runnable}
 1379         * or {@code Callable}. Finally, either a list of result objects is returned, or the JVM is terminated if an exit
 1380         * code {@linkplain #andExit(int) was set}. If any of the {@code CommandLine} commands does not implement either
 1381         * {@code Runnable} or {@code Callable}, an {@code ExecutionException}
 1382         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
 1383         *
 1384         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
 1385         * @param out the {@code PrintStream} to print help to if requested
 1386         * @param ansi for printing help messages using ANSI styles and colors
 1387         * @return an empty list if help was requested, or a list containing the result of executing all commands:
 1388         *      the return values from calling the {@code Callable} commands, {@code null} elements for commands that implement {@code Runnable}
 1389         * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions}
 1390         *      thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler}
 1391         * @throws ExecutionException if a problem occurred while processing the parse results; use
 1392         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1393         */
 1394        public List<Object> handleParseResult(List<CommandLine> parsedCommands, PrintStream out, Help.Ansi ansi) {
 1395            if (printHelpIfRequested(parsedCommands, out, err(), ansi)) { return returnResultOrExit(Collections.emptyList()); }
 1396            List<Object> result = new ArrayList<Object>();
 1397            for (CommandLine parsed : parsedCommands) {
 1398                execute(parsed, result);
 1399            }
 1400            return returnResultOrExit(result);
 1401        }
 1402        /** Executes the top-level command and all subcommands as {@code Runnable} or {@code Callable}.
 1403         * If any of the {@code CommandLine} commands does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
 1404         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
 1405         *
 1406         * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
 1407         * @return an empty list if help was requested, or a list containing the result of executing all commands:
 1408         *      the return values from calling the {@code Callable} commands, {@code null} elements for commands that implement {@code Runnable}
 1409         * @throws ExecutionException if a problem occurred while processing the parse results; use
 1410         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1411         * @since 3.0 */
 1412        protected List<Object> handle(ParseResult parseResult) throws ExecutionException {
 1413            List<Object> result = new ArrayList<Object>();
 1414            execute(parseResult.commandSpec().commandLine(), result);
 1415            while (parseResult.hasSubcommand()) {
 1416                parseResult = parseResult.subcommand();
 1417                execute(parseResult.commandSpec().commandLine(), result);
 1418            }
 1419            return returnResultOrExit(result);
 1420        }
 1421        @Override protected RunAll self() { return this; }
 1422    }
 1423
 1424    /** @deprecated use {@link #parseWithHandler(IParseResultHandler2,  String[])} instead
 1425     * @since 2.0 */
 1426    @Deprecated public List<Object> parseWithHandler(IParseResultHandler handler, PrintStream out, String... args) {
 1427        return parseWithHandlers(handler, out, Help.Ansi.AUTO, defaultExceptionHandler(), args);
 1428    }
 1429    /**
 1430     * Returns the result of calling {@link #parseWithHandlers(IParseResultHandler2,  IExceptionHandler2, String...)} with
 1431     * a new {@link DefaultExceptionHandler} in addition to the specified parse result handler and the specified command line arguments.
 1432     * <p>
 1433     * This is a convenience method intended to offer the same ease of use as the {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run}
 1434     * and {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call} methods, but with more flexibility and better
 1435     * support for nested subcommands.
 1436     * </p>
 1437     * <p>Calling this method roughly expands to:</p>
 1438     * <pre>{@code
 1439     * try {
 1440     *     ParseResult parseResult = parseArgs(args);
 1441     *     return handler.handleParseResult(parseResult);
 1442     * } catch (ParameterException ex) {
 1443     *     return new DefaultExceptionHandler<R>().handleParseException(ex, args);
 1444     * }
 1445     * }</pre>
 1446     * <p>
 1447     * Picocli provides some default handlers that allow you to accomplish some common tasks with very little code.
 1448     * The following handlers are available:</p>
 1449     * <ul>
 1450     *   <li>{@link RunLast} handler prints help if requested, and otherwise gets the last specified command or subcommand
 1451     * and tries to execute it as a {@code Runnable} or {@code Callable}.</li>
 1452     *   <li>{@link RunFirst} handler prints help if requested, and otherwise executes the top-level command as a {@code Runnable} or {@code Callable}.</li>
 1453     *   <li>{@link RunAll} handler prints help if requested, and otherwise executes all recognized commands and subcommands as {@code Runnable} or {@code Callable} tasks.</li>
 1454     *   <li>{@link DefaultExceptionHandler} prints the error message followed by usage help</li>
 1455     * </ul>
 1456     * @param <R> the return type of this handler
 1457     * @param handler the function that will handle the result of successfully parsing the command line arguments
 1458     * @param args the command line arguments
 1459     * @return an object resulting from handling the parse result or the exception that occurred while parsing the input
 1460     * @throws ExecutionException if the command line arguments were parsed successfully but a problem occurred while processing the
 1461     *      parse results; use {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1462     * @see RunLast
 1463     * @see RunAll
 1464     * @since 3.0 */
 1465    public <R> R parseWithHandler(IParseResultHandler2<R> handler, String[] args) {
 1466        return parseWithHandlers(handler, new DefaultExceptionHandler<R>(), args);
 1467    }
 1468
 1469    /** @deprecated use {@link #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)} instead
 1470     * @since 2.0 */
 1471    @Deprecated public List<Object> parseWithHandlers(IParseResultHandler handler, PrintStream out, Help.Ansi ansi, IExceptionHandler exceptionHandler, String... args) {
 1472        try {
 1473            List<CommandLine> result = parse(args);
 1474            return handler.handleParseResult(result, out, ansi);
 1475        } catch (ParameterException ex) {
 1476            return exceptionHandler.handleException(ex, out, ansi, args);
 1477        }
 1478    }
 1479    /**
 1480     * Tries to {@linkplain #parseArgs(String...) parse} the specified command line arguments, and if successful, delegates
 1481     * the processing of the resulting {@code ParseResult} object to the specified {@linkplain IParseResultHandler2 handler}.
 1482     * If the command line arguments were invalid, the {@code ParameterException} thrown from the {@code parse} method
 1483     * is caught and passed to the specified {@link IExceptionHandler2}.
 1484     * <p>
 1485     * This is a convenience method intended to offer the same ease of use as the {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run}
 1486     * and {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call} methods, but with more flexibility and better
 1487     * support for nested subcommands.
 1488     * </p>
 1489     * <p>Calling this method roughly expands to:</p>
 1490     * <pre>
 1491     * ParseResult parseResult = null;
 1492     * try {
 1493     *     parseResult = parseArgs(args);
 1494     *     return handler.handleParseResult(parseResult);
 1495     * } catch (ParameterException ex) {
 1496     *     return exceptionHandler.handleParseException(ex, (String[]) args);
 1497     * } catch (ExecutionException ex) {
 1498     *     return exceptionHandler.handleExecutionException(ex, parseResult);
 1499     * }
 1500     * </pre>
 1501     * <p>
 1502     * Picocli provides some default handlers that allow you to accomplish some common tasks with very little code.
 1503     * The following handlers are available:</p>
 1504     * <ul>
 1505     *   <li>{@link RunLast} handler prints help if requested, and otherwise gets the last specified command or subcommand
 1506     * and tries to execute it as a {@code Runnable} or {@code Callable}.</li>
 1507     *   <li>{@link RunFirst} handler prints help if requested, and otherwise executes the top-level command as a {@code Runnable} or {@code Callable}.</li>
 1508     *   <li>{@link RunAll} handler prints help if requested, and otherwise executes all recognized commands and subcommands as {@code Runnable} or {@code Callable} tasks.</li>
 1509     *   <li>{@link DefaultExceptionHandler} prints the error message followed by usage help</li>
 1510     * </ul>
 1511     *
 1512     * @param handler the function that will handle the result of successfully parsing the command line arguments
 1513     * @param exceptionHandler the function that can handle the {@code ParameterException} thrown when the command line arguments are invalid
 1514     * @param args the command line arguments
 1515     * @return an object resulting from handling the parse result or the exception that occurred while parsing the input
 1516     * @throws ExecutionException if the command line arguments were parsed successfully but a problem occurred while processing the parse
 1517     *      result {@code ParseResult} object; use {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1518     * @param <R> the return type of the result handler and exception handler
 1519     * @see RunLast
 1520     * @see RunAll
 1521     * @see DefaultExceptionHandler
 1522     * @since 3.0 */
 1523    public <R> R parseWithHandlers(IParseResultHandler2<R> handler, IExceptionHandler2<R> exceptionHandler, String... args) {
 1524        ParseResult parseResult = null;
 1525        try {
 1526            parseResult = parseArgs(args);
 1527            return handler.handleParseResult(parseResult);
 1528        } catch (ParameterException ex) {
 1529            return exceptionHandler.handleParseException(ex, args);
 1530        } catch (ExecutionException ex) {
 1531            return exceptionHandler.handleExecutionException(ex, parseResult);
 1532        }
 1533    }
 1534    static String versionString() {
 1535        return String.format("%s, JVM: %s (%s %s %s), OS: %s %s %s", VERSION,
 1536                System.getProperty("java.version"), System.getProperty("java.vendor"), System.getProperty("java.vm.name"), System.getProperty("java.vm.version"),
 1537                System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch"));
 1538    }
 1539    /**
 1540     * Equivalent to {@code new CommandLine(command).usage(out)}. See {@link #usage(PrintStream)} for details.
 1541     * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters}
 1542     * @param out the print stream to print the help message to
 1543     * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1544     */
 1545    public static void usage(Object command, PrintStream out) {
 1546        toCommandLine(command, new DefaultFactory()).usage(out);
 1547    }
 1548
 1549    /**
 1550     * Equivalent to {@code new CommandLine(command).usage(out, ansi)}.
 1551     * See {@link #usage(PrintStream, Help.Ansi)} for details.
 1552     * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters}
 1553     * @param out the print stream to print the help message to
 1554     * @param ansi whether the usage message should contain ANSI escape codes or not
 1555     * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1556     */
 1557    public static void usage(Object command, PrintStream out, Help.Ansi ansi) {
 1558        toCommandLine(command, new DefaultFactory()).usage(out, ansi);
 1559    }
 1560
 1561    /**
 1562     * Equivalent to {@code new CommandLine(command).usage(out, colorScheme)}.
 1563     * See {@link #usage(PrintStream, Help.ColorScheme)} for details.
 1564     * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters}
 1565     * @param out the print stream to print the help message to
 1566     * @param colorScheme the {@code ColorScheme} defining the styles for options, parameters and commands when ANSI is enabled
 1567     * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1568     */
 1569    public static void usage(Object command, PrintStream out, Help.ColorScheme colorScheme) {
 1570        toCommandLine(command, new DefaultFactory()).usage(out, colorScheme);
 1571    }
 1572
 1573    /**
 1574     * Delegates to {@link #usage(PrintStream, Help.Ansi)} with the {@linkplain Help.Ansi#AUTO platform default}.
 1575     * @param out the printStream to print to
 1576     * @see #usage(PrintStream, Help.ColorScheme)
 1577     */
 1578    public void usage(PrintStream out) { usage(out, Help.Ansi.AUTO); }
 1579    /**
 1580     * Delegates to {@link #usage(PrintWriter, Help.Ansi)} with the {@linkplain Help.Ansi#AUTO platform default}.
 1581     * @param writer the PrintWriter to print to
 1582     * @see #usage(PrintWriter, Help.ColorScheme)
 1583     * @since 3.0 */
 1584    public void usage(PrintWriter writer) { usage(writer, Help.Ansi.AUTO); }
 1585
 1586    /**
 1587     * Delegates to {@link #usage(PrintStream, Help.ColorScheme)} with the {@linkplain Help#defaultColorScheme(CommandLine.Help.Ansi) default color scheme}.
 1588     * @param out the printStream to print to
 1589     * @param ansi whether the usage message should include ANSI escape codes or not
 1590     * @see #usage(PrintStream, Help.ColorScheme)
 1591     */
 1592    public void usage(PrintStream out, Help.Ansi ansi) { usage(out, Help.defaultColorScheme(ansi)); }
 1593    /** Similar to {@link #usage(PrintStream, Help.Ansi)} but with the specified {@code PrintWriter} instead of a {@code PrintStream}.
 1594     * @since 3.0 */
 1595    public void usage(PrintWriter writer, Help.Ansi ansi) { usage(writer, Help.defaultColorScheme(ansi)); }
 1596
 1597    /**
 1598     * Prints a usage help message for the annotated command class to the specified {@code PrintStream}.
 1599     * Delegates construction of the usage help message to the {@link Help} inner class and is equivalent to:
 1600     * <pre>
 1601     * Help.ColorScheme colorScheme = Help.defaultColorScheme(Help.Ansi.AUTO);
 1602     * Help help = getHelpFactory().create(getCommandSpec(), colorScheme)
 1603     * StringBuilder sb = new StringBuilder();
 1604     * for (String key : getHelpSectionKeys()) {
 1605     *     IHelpSectionRenderer renderer = getHelpSectionMap().get(key);
 1606     *     if (renderer != null) { sb.append(renderer.render(help)); }
 1607     * }
 1608     * out.print(sb);
 1609     * </pre>
 1610     * <p>Annotate your class with {@link Command} to control many aspects of the usage help message, including
 1611     * the program name, text of section headings and section contents, and some aspects of the auto-generated sections
 1612     * of the usage help message.
 1613     * <p>To customize the auto-generated sections of the usage help message, like how option details are displayed,
 1614     * instantiate a {@link Help} object and use a {@link Help.TextTable} with more of fewer columns, a custom
 1615     * {@linkplain Help.Layout layout}, and/or a custom option {@linkplain Help.IOptionRenderer renderer}
 1616     * for ultimate control over which aspects of an Option or Field are displayed where.</p>
 1617     * @param out the {@code PrintStream} to print the usage help message to
 1618     * @param colorScheme the {@code ColorScheme} defining the styles for options, parameters and commands when ANSI is enabled
 1619     * @see UsageMessageSpec
 1620     */
 1621    public void usage(PrintStream out, Help.ColorScheme colorScheme) {
 1622        out.print(usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), colorScheme)));
 1623    }
 1624    /** Similar to {@link #usage(PrintStream, Help.ColorScheme)}, but with the specified {@code PrintWriter} instead of a {@code PrintStream}.
 1625     * @since 3.0 */
 1626    public void usage(PrintWriter writer, Help.ColorScheme colorScheme) {
 1627        writer.print(usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), colorScheme)));
 1628    }
 1629    /** Similar to {@link #usage(PrintStream)}, but returns the usage help message as a String instead of printing it to the {@code PrintStream}.
 1630     * @since 3.2 */
 1631    public String getUsageMessage() {
 1632        return usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), Help.defaultColorScheme(Help.Ansi.AUTO))).toString();
 1633    }
 1634    /** Similar to {@link #usage(PrintStream, Help.Ansi)}, but returns the usage help message as a String instead of printing it to the {@code PrintStream}.
 1635     * @since 3.2 */
 1636    public String getUsageMessage(Help.Ansi ansi) {
 1637        return usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), Help.defaultColorScheme(ansi))).toString();
 1638    }
 1639    /** Similar to {@link #usage(PrintStream, Help.ColorScheme)}, but returns the usage help message as a String instead of printing it to the {@code PrintStream}.
 1640     * @since 3.2 */
 1641    public String getUsageMessage(Help.ColorScheme colorScheme) {
 1642        return usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), colorScheme)).toString();
 1643    }
 1644
 1645    private StringBuilder usage(StringBuilder sb, Help help) {
 1646        for (String key : getHelpSectionKeys()) {
 1647            IHelpSectionRenderer renderer = getHelpSectionMap().get(key);
 1648            if (renderer != null) { sb.append(renderer.render(help)); }
 1649        }
 1650        return sb;
 1651    }
 1652
 1653    /**
 1654     * Delegates to {@link #printVersionHelp(PrintStream, Help.Ansi)} with the {@linkplain Help.Ansi#AUTO platform default}.
 1655     * @param out the printStream to print to
 1656     * @see #printVersionHelp(PrintStream, Help.Ansi)
 1657     * @since 0.9.8
 1658     */
 1659    public void printVersionHelp(PrintStream out) { printVersionHelp(out, Help.Ansi.AUTO); }
 1660
 1661    /**
 1662     * Prints version information from the {@link Command#version()} annotation to the specified {@code PrintStream}.
 1663     * Each element of the array of version strings is printed on a separate line. Version strings may contain
 1664     * <a href="http://picocli.info/#_usage_help_with_styles_and_colors">markup for colors and style</a>.
 1665     * @param out the printStream to print to
 1666     * @param ansi whether the usage message should include ANSI escape codes or not
 1667     * @see Command#version()
 1668     * @see Option#versionHelp()
 1669     * @see #isVersionHelpRequested()
 1670     * @since 0.9.8
 1671     */
 1672    public void printVersionHelp(PrintStream out, Help.Ansi ansi) {
 1673        for (String versionInfo : getCommandSpec().version()) {
 1674            out.println(ansi.new Text(versionInfo));
 1675        }
 1676    }
 1677    /**
 1678     * Prints version information from the {@link Command#version()} annotation to the specified {@code PrintStream}.
 1679     * Each element of the array of version strings is {@linkplain String#format(String, Object...) formatted} with the
 1680     * specified parameters, and printed on a separate line. Both version strings and parameters may contain
 1681     * <a href="http://picocli.info/#_usage_help_with_styles_and_colors">markup for colors and style</a>.
 1682     * @param out the printStream to print to
 1683     * @param ansi whether the usage message should include ANSI escape codes or not
 1684     * @param params Arguments referenced by the format specifiers in the version strings
 1685     * @see Command#version()
 1686     * @see Option#versionHelp()
 1687     * @see #isVersionHelpRequested()
 1688     * @since 1.0.0
 1689     */
 1690    public void printVersionHelp(PrintStream out, Help.Ansi ansi, Object... params) {
 1691        for (String versionInfo : getCommandSpec().version()) {
 1692            out.println(ansi.new Text(format(versionInfo, params)));
 1693        }
 1694    }
 1695
 1696    /**
 1697     * Delegates to {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.out} for
 1698     * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 1699     * @param callable the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1700     * @param args the command line arguments to parse
 1701     * @param <C> the annotated object must implement Callable
 1702     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1703     * @see #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)
 1704     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1705     * @throws ExecutionException if the Callable throws an exception
 1706     * @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
 1707     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1708     * @since 3.0
 1709     */
 1710    public static <C extends Callable<T>, T> T call(C callable, String... args) {
 1711        return call(callable, System.out, System.err, Help.Ansi.AUTO, args);
 1712    }
 1713
 1714    /**
 1715     * Delegates to {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.err} for
 1716     * diagnostic error messages and {@link Help.Ansi#AUTO}.
 1717     * @param callable the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1718     * @param out the printStream to print the usage help message to when the user requested help
 1719     * @param args the command line arguments to parse
 1720     * @param <C> the annotated object must implement Callable
 1721     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1722     * @see #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)
 1723     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1724     * @throws ExecutionException if the Callable throws an exception
 1725     * @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
 1726     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1727     * @see RunLast
 1728     */
 1729    public static <C extends Callable<T>, T> T call(C callable, PrintStream out, String... args) {
 1730        return call(callable, out, System.err, Help.Ansi.AUTO, args);
 1731    }
 1732    /**
 1733     * Delegates to {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.err} for diagnostic error messages.
 1734     * @param callable the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1735     * @param out the printStream to print the usage help message to when the user requested help
 1736     * @param ansi the ANSI style to use
 1737     * @param args the command line arguments to parse
 1738     * @param <C> the annotated object must implement Callable
 1739     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1740     * @see #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)
 1741     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1742     * @throws ExecutionException if the Callable throws an exception
 1743     * @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
 1744     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1745     * @see RunLast
 1746     */
 1747    public static <C extends Callable<T>, T> T call(C callable, PrintStream out, Help.Ansi ansi, String... args) {
 1748        return call(callable, out, System.err, ansi, args);
 1749    }
 1750    /**
 1751     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
 1752     * The annotated object needs to implement {@link Callable}. Calling this method is equivalent to:
 1753     * <pre>{@code
 1754     * CommandLine cmd = new CommandLine(callable);
 1755     * List<Object> results = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi),
 1756     *                                              new DefaultExceptionHandler().useErr(err).useAnsi(ansi),
 1757     *                                              args);
 1758     * T result = results == null || results.isEmpty() ? null : (T) results.get(0);
 1759     * return result;
 1760     * }</pre>
 1761     * <p>
 1762     * If the specified Callable command has subcommands, the {@linkplain RunLast last} subcommand specified on the
 1763     * command line is executed.
 1764     * Commands with subcommands may be interested in calling the {@link #parseWithHandler(IParseResultHandler2, String[]) parseWithHandler}
 1765     * method with the {@link RunAll} handler or a custom handler.
 1766     * </p><p>
 1767     * Use {@link #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...) call(Class, IFactory, ...)} instead of this method
 1768     * if you want to use a factory that performs Dependency Injection.
 1769     * </p>
 1770     * @param callable the command to call when {@linkplain #parse(String...) parsing} succeeds.
 1771     * @param out the printStream to print the usage help message to when the user requested help
 1772     * @param err the printStream to print diagnostic messages to
 1773     * @param ansi whether the usage message should include ANSI escape codes or not
 1774     * @param args the command line arguments to parse
 1775     * @param <C> the annotated object must implement Callable
 1776     * @param <T> the return type of the specified {@code Callable}
 1777     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1778     * @throws ExecutionException if the Callable throws an exception
 1779     * @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
 1780     * @see #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1781     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1782     * @see RunLast
 1783     * @since 3.0
 1784     */
 1785    public static <C extends Callable<T>, T> T call(C callable, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) {
 1786        CommandLine cmd = new CommandLine(callable);
 1787        List<Object> results = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler<List<Object>>().useErr(err).useAnsi(ansi), args);
 1788        @SuppressWarnings("unchecked") T result = (results == null || results.isEmpty()) ? null : (T) results.get(0);
 1789        return result;
 1790    }
 1791    /**
 1792     * Delegates to {@link #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.out} for
 1793     * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 1794     * @param callableClass class of the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1795     * @param factory the factory responsible for instantiating the specified callable class and potentially inject other components
 1796     * @param args the command line arguments to parse
 1797     * @param <C> the annotated class must implement Callable
 1798     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1799     * @see #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1800     * @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
 1801     * @throws ExecutionException if the Callable throws an exception
 1802     * @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
 1803     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1804     * @since 3.2
 1805     */
 1806    public static <C extends Callable<T>, T> T call(Class<C> callableClass, IFactory factory, String... args) {
 1807        return call(callableClass, factory, System.out, System.err, Help.Ansi.AUTO, args);
 1808    }
 1809    /**
 1810     * Delegates to {@link #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with
 1811     * {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 1812     * @param callableClass class of the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1813     * @param factory the factory responsible for instantiating the specified callable class and potentially injecting other components
 1814     * @param out the printStream to print the usage help message to when the user requested help
 1815     * @param args the command line arguments to parse
 1816     * @param <C> the annotated class must implement Callable
 1817     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1818     * @see #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1819     * @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
 1820     * @throws ExecutionException if the Callable throws an exception
 1821     * @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
 1822     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1823     * @since 3.2
 1824     */
 1825    public static <C extends Callable<T>, T> T call(Class<C> callableClass, IFactory factory, PrintStream out, String... args) {
 1826        return call(callableClass, factory, out, System.err, Help.Ansi.AUTO, args);
 1827    }
 1828    /**
 1829     * Delegates to {@link #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with
 1830     * {@code System.err} for diagnostic error messages.
 1831     * @param callableClass class of the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1832     * @param factory the factory responsible for instantiating the specified callable class and potentially injecting other components
 1833     * @param out the printStream to print the usage help message to when the user requested help
 1834     * @param ansi the ANSI style to use
 1835     * @param args the command line arguments to parse
 1836     * @param <C> the annotated class must implement Callable
 1837     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1838     * @see #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1839     * @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
 1840     * @throws ExecutionException if the Callable throws an exception
 1841     * @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
 1842     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1843     * @since 3.2
 1844     */
 1845    public static <C extends Callable<T>, T> T call(Class<C> callableClass, IFactory factory, PrintStream out, Help.Ansi ansi, String... args) {
 1846        return call(callableClass, factory, out, System.err, ansi, args);
 1847    }
 1848    /**
 1849     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
 1850     * The specified {@linkplain IFactory factory} will create an instance of the specified {@code callableClass};
 1851     * use this method instead of {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call(Callable, ...)}
 1852     * if you want to use a factory that performs Dependency Injection.
 1853     * The annotated class needs to implement {@link Callable}. Calling this method is equivalent to:
 1854     * <pre>{@code
 1855     * CommandLine cmd = new CommandLine(callableClass, factory);
 1856     * List<Object> results = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi),
 1857     *                                              new DefaultExceptionHandler().useErr(err).useAnsi(ansi),
 1858     *                                              args);
 1859     * T result = results == null || results.isEmpty() ? null : (T) results.get(0);
 1860     * return result;
 1861     * }</pre>
 1862     * <p>
 1863     * If the specified Callable command has subcommands, the {@linkplain RunLast last} subcommand specified on the
 1864     * command line is executed.
 1865     * Commands with subcommands may be interested in calling the {@link #parseWithHandler(IParseResultHandler2, String[]) parseWithHandler}
 1866     * method with the {@link RunAll} handler or a custom handler.
 1867     * </p>
 1868     * @param callableClass class of the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1869     * @param factory the factory responsible for instantiating the specified callable class and potentially injecting other components
 1870     * @param out the printStream to print the usage help message to when the user requested help
 1871     * @param err the printStream to print diagnostic messages to
 1872     * @param ansi the ANSI style to use
 1873     * @param args the command line arguments to parse
 1874     * @param <C> the annotated class must implement Callable
 1875     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1876     * @see #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1877     * @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
 1878     * @throws ExecutionException if the Callable throws an exception
 1879     * @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
 1880     * @see #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)
 1881     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1882     * @since 3.2
 1883     */
 1884    public static <C extends Callable<T>, T> T call(Class<C> callableClass, IFactory factory, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) {
 1885        CommandLine cmd = new CommandLine(callableClass, factory);
 1886        List<Object> results = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler<List<Object>>().useErr(err).useAnsi(ansi), args);
 1887        @SuppressWarnings("unchecked") T result = (results == null || results.isEmpty()) ? null : (T) results.get(0);
 1888        return result;
 1889    }
 1890
 1891    /**
 1892     * Delegates to {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.out} for
 1893     * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 1894     * @param runnable the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 1895     * @param args the command line arguments to parse
 1896     * @param <R> the annotated object must implement Runnable
 1897     * @see #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)
 1898     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1899     * @throws ExecutionException if the Runnable throws an exception
 1900     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1901     * @see RunLast
 1902     * @since 3.0
 1903     */
 1904    public static <R extends Runnable> void run(R runnable, String... args) {
 1905        run(runnable, System.out, System.err, Help.Ansi.AUTO, args);
 1906    }
 1907
 1908    /**
 1909     * Delegates to {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.err} for diagnostic error messages and {@link Help.Ansi#AUTO}.
 1910     * @param runnable the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 1911     * @param out the printStream to print the usage help message to when the user requested help
 1912     * @param args the command line arguments to parse
 1913     * @param <R> the annotated object must implement Runnable
 1914     * @see #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)
 1915     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1916     * @throws ExecutionException if the Runnable throws an exception
 1917     * @see #parseWithHandler(IParseResultHandler2, String[])
 1918     * @see RunLast
 1919     */
 1920    public static <R extends Runnable> void run(R runnable, PrintStream out, String... args) {
 1921        run(runnable, out, System.err, Help.Ansi.AUTO, args);
 1922    }
 1923    /**
 1924     * Delegates to {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.err} for diagnostic error messages.
 1925     * @param runnable the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 1926     * @param out the printStream to print the usage help message to when the user requested help
 1927     * @param ansi whether the usage message should include ANSI escape codes or not
 1928     * @param args the command line arguments to parse
 1929     * @param <R> the annotated object must implement Runnable
 1930     * @see #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)
 1931     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1932     * @throws ExecutionException if the Runnable throws an exception
 1933     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1934     * @see RunLast
 1935     */
 1936    public static <R extends Runnable> void run(R runnable, PrintStream out, Help.Ansi ansi, String... args) {
 1937        run(runnable, out, System.err, ansi, args);
 1938    }
 1939    /**
 1940     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
 1941     * The annotated object needs to implement {@link Runnable}. Calling this method is equivalent to:
 1942     * <pre>{@code
 1943     * CommandLine cmd = new CommandLine(runnable);
 1944     * cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi),
 1945     *                       new DefaultExceptionHandler().useErr(err).useAnsi(ansi),
 1946     *                       args);
 1947     * }</pre>
 1948     * <p>
 1949     * If the specified Runnable command has subcommands, the {@linkplain RunLast last} subcommand specified on the
 1950     * command line is executed.
 1951     * Commands with subcommands may be interested in calling the {@link #parseWithHandler(IParseResultHandler2, String[]) parseWithHandler}
 1952     * method with the {@link RunAll} handler or a custom handler.
 1953     * </p><p>
 1954     * From picocli v2.0, this method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi) requested},
 1955     * and any exceptions thrown by the {@code Runnable} are caught and rethrown wrapped in an {@code ExecutionException}.
 1956     * </p><p>
 1957     * Use {@link #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...) run(Class, IFactory, ...)} instead of this method
 1958     * if you want to use a factory that performs Dependency Injection.
 1959     * </p>
 1960     * @param runnable the command to run when {@linkplain #parse(String...) parsing} succeeds.
 1961     * @param out the printStream to print the usage help message to when the user requested help
 1962     * @param err the printStream to print diagnostic messages to
 1963     * @param ansi whether the usage message should include ANSI escape codes or not
 1964     * @param args the command line arguments to parse
 1965     * @param <R> the annotated object must implement Runnable
 1966     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1967     * @throws ExecutionException if the Runnable throws an exception
 1968     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1969     * @see RunLast
 1970     * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1971     * @since 3.0
 1972     */
 1973    public static <R extends Runnable> void run(R runnable, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) {
 1974        CommandLine cmd = new CommandLine(runnable);
 1975        cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler<List<Object>>().useErr(err).useAnsi(ansi), args);
 1976    }
 1977    /**
 1978     * Delegates to {@link #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.out} for
 1979     * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 1980     * @param runnableClass class of the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 1981     * @param factory the factory responsible for instantiating the specified Runnable class and potentially injecting other components
 1982     * @param args the command line arguments to parse
 1983     * @param <R> the annotated class must implement Runnable
 1984     * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1985     * @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
 1986     * @throws ExecutionException if the Runnable throws an exception
 1987     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1988     * @see RunLast
 1989     * @since 3.2
 1990     */
 1991    public static <R extends Runnable> void run(Class<R> runnableClass, IFactory factory, String... args) {
 1992        run(runnableClass, factory, System.out, System.err, Help.Ansi.AUTO, args);
 1993    }
 1994    /**
 1995     * Delegates to {@link #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with
 1996     * {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 1997     * @param runnableClass class of the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 1998     * @param factory the factory responsible for instantiating the specified Runnable class and potentially injecting other components
 1999     * @param out the printStream to print the usage help message to when the user requested help
 2000     * @param args the command line arguments to parse
 2001     * @param <R> the annotated class must implement Runnable
 2002     * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 2003     * @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
 2004     * @throws ExecutionException if the Runnable throws an exception
 2005     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2006     * @see RunLast
 2007     * @since 3.2
 2008     */
 2009    public static <R extends Runnable> void run(Class<R> runnableClass, IFactory factory, PrintStream out, String... args) {
 2010        run(runnableClass, factory, out, System.err, Help.Ansi.AUTO, args);
 2011    }
 2012    /**
 2013     * Delegates to {@link #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with
 2014     * {@code System.err} for diagnostic error messages.
 2015     * @param runnableClass class of the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 2016     * @param factory the factory responsible for instantiating the specified Runnable class and potentially injecting other components
 2017     * @param out the printStream to print the usage help message to when the user requested help
 2018     * @param ansi whether the usage message should include ANSI escape codes or not
 2019     * @param args the command line arguments to parse
 2020     * @param <R> the annotated class must implement Runnable
 2021     * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 2022     * @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
 2023     * @throws ExecutionException if the Runnable throws an exception
 2024     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2025     * @see RunLast
 2026     * @since 3.2
 2027     */
 2028    public static <R extends Runnable> void run(Class<R> runnableClass, IFactory factory, PrintStream out, Help.Ansi ansi, String... args) {
 2029        run(runnableClass, factory, out, System.err, ansi, args);
 2030    }
 2031    /**
 2032     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
 2033     * The specified {@linkplain IFactory factory} will create an instance of the specified {@code runnableClass};
 2034     * use this method instead of {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run(Runnable, ...)}
 2035     * if you want to use a factory that performs Dependency Injection.
 2036     * The annotated class needs to implement {@link Runnable}. Calling this method is equivalent to:
 2037     * <pre>{@code
 2038     * CommandLine cmd = new CommandLine(runnableClass, factory);
 2039     * cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi),
 2040     *                       new DefaultExceptionHandler().useErr(err).useAnsi(ansi),
 2041     *                       args);
 2042     * }</pre>
 2043     * <p>
 2044     * If the specified Runnable command has subcommands, the {@linkplain RunLast last} subcommand specified on the
 2045     * command line is executed.
 2046     * Commands with subcommands may be interested in calling the {@link #parseWithHandler(IParseResultHandler2, String[]) parseWithHandler}
 2047     * method with the {@link RunAll} handler or a custom handler.
 2048     * </p><p>
 2049     * This method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi) requested},
 2050     * and any exceptions thrown by the {@code Runnable} are caught and rethrown wrapped in an {@code ExecutionException}.
 2051     * </p>
 2052     * @param runnableClass class of the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 2053     * @param factory the factory responsible for instantiating the specified Runnable class and potentially injecting other components
 2054     * @param out the printStream to print the usage help message to when the user requested help
 2055     * @param err the printStream to print diagnostic messages to
 2056     * @param ansi whether the usage message should include ANSI escape codes or not
 2057     * @param args the command line arguments to parse
 2058     * @param <R> the annotated class must implement Runnable
 2059     * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 2060     * @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
 2061     * @throws ExecutionException if the Runnable throws an exception
 2062     * @see #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)
 2063     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2064     * @see RunLast
 2065     * @since 3.2
 2066     */
 2067    public static <R extends Runnable> void run(Class<R> runnableClass, IFactory factory, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) {
 2068        CommandLine cmd = new CommandLine(runnableClass, factory);
 2069        cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler<List<Object>>().useErr(err).useAnsi(ansi), args);
 2070    }
 2071
 2072    /**
 2073     * Delegates to {@link #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.out} for
 2074     * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 2075     * @param methodName the {@code @Command}-annotated method to build a {@link CommandSpec} model from,
 2076     *                   and run when {@linkplain #parseArgs(String...) parsing} succeeds.
 2077     * @param cls the class where the {@code @Command}-annotated method is declared, or a subclass
 2078     * @param args the command line arguments to parse
 2079     * @see #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)
 2080     * @throws InitializationException if the specified method does not have a {@link Command} annotation,
 2081     *      or if the specified class contains multiple {@code @Command}-annotated methods with the specified name
 2082     * @throws ExecutionException if the Runnable throws an exception
 2083     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2084     * @since 3.6
 2085     */
 2086    public static Object invoke(String methodName, Class<?> cls, String... args) {
 2087        return invoke(methodName, cls, System.out, System.err, Help.Ansi.AUTO, args);
 2088    }
 2089    /**
 2090     * Delegates to {@link #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)} with the specified stream for
 2091     * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 2092     * @param methodName the {@code @Command}-annotated method to build a {@link CommandSpec} model from,
 2093     *                   and run when {@linkplain #parseArgs(String...) parsing} succeeds.
 2094     * @param cls the class where the {@code @Command}-annotated method is declared, or a subclass
 2095     * @param out the printstream to print requested help message to
 2096     * @param args the command line arguments to parse
 2097     * @see #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)
 2098     * @throws InitializationException if the specified method does not have a {@link Command} annotation,
 2099     *      or if the specified class contains multiple {@code @Command}-annotated methods with the specified name
 2100     * @throws ExecutionException if the Runnable throws an exception
 2101     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2102     * @since 3.6
 2103     */
 2104    public static Object invoke(String methodName, Class<?> cls, PrintStream out, String... args) {
 2105        return invoke(methodName, cls, out, System.err, Help.Ansi.AUTO, args);
 2106    }
 2107    /**
 2108     * Delegates to {@link #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)} with the specified stream for
 2109     * requested usage help messages, {@code System.err} for diagnostic error messages, and the specified Ansi mode.
 2110     * @param methodName the {@code @Command}-annotated method to build a {@link CommandSpec} model from,
 2111     *                   and run when {@linkplain #parseArgs(String...) parsing} succeeds.
 2112     * @param cls the class where the {@code @Command}-annotated method is declared, or a subclass
 2113     * @param out the printstream to print requested help message to
 2114     * @param ansi whether the usage message should include ANSI escape codes or not
 2115     * @param args the command line arguments to parse
 2116     * @see #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)
 2117     * @throws InitializationException if the specified method does not have a {@link Command} annotation,
 2118     *      or if the specified class contains multiple {@code @Command}-annotated methods with the specified name
 2119     * @throws ExecutionException if the Runnable throws an exception
 2120     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2121     * @since 3.6
 2122     */
 2123    public static Object invoke(String methodName, Class<?> cls, PrintStream out, Help.Ansi ansi, String... args) {
 2124        return invoke(methodName, cls, out, System.err, ansi, args);
 2125    }
 2126    /**
 2127     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
 2128     * Constructs a {@link CommandSpec} model from the {@code @Option} and {@code @Parameters}-annotated method parameters
 2129     * of the {@code @Command}-annotated method, parses the specified command line arguments and invokes the specified method.
 2130     * Calling this method is equivalent to:
 2131     * <pre>{@code
 2132     * Method commandMethod = getCommandMethods(cls, methodName).get(0);
 2133     * CommandLine cmd = new CommandLine(commandMethod);
 2134     * List<Object> list = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi),
 2135     *                                           new DefaultExceptionHandler().useErr(err).useAnsi(ansi),
 2136     *                                           args);
 2137     * return list == null ? null : list.get(0);
 2138     * }</pre>
 2139     * @param methodName the {@code @Command}-annotated method to build a {@link CommandSpec} model from,
 2140     *                   and run when {@linkplain #parseArgs(String...) parsing} succeeds.
 2141     * @param cls the class where the {@code @Command}-annotated method is declared, or a subclass
 2142     * @param out the printStream to print the usage help message to when the user requested help
 2143     * @param err the printStream to print diagnostic messages to
 2144     * @param ansi whether the usage message should include ANSI escape codes or not
 2145     * @param args the command line arguments to parse
 2146     * @throws InitializationException if the specified method does not have a {@link Command} annotation,
 2147     *      or if the specified class contains multiple {@code @Command}-annotated methods with the specified name
 2148     * @throws ExecutionException if the method throws an exception
 2149     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2150     * @since 3.6
 2151     */
 2152    public static Object invoke(String methodName, Class<?> cls, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) {
 2153        List<Method> candidates = getCommandMethods(cls, methodName);
 2154        if (candidates.size() != 1) { throw new InitializationException("Expected exactly one @Command-annotated method for " + cls.getName() + "::" + methodName + "(...), but got: " + candidates); }
 2155        Method method = candidates.get(0);
 2156        CommandLine cmd = new CommandLine(method);
 2157        List<Object> list = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler<List<Object>>().useErr(err).useAnsi(ansi), args);
 2158        return list == null ? null : list.get(0);
 2159    }
 2160
 2161    /**
 2162     * 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}).
 2163     * 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.
 2164     *
 2165     * @param cls the class to search for methods annotated with {@code @Command}
 2166     * @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}.
 2167     * @return the matching command methods, or an empty list
 2168     * @see #invoke(String, Class, String...)
 2169     * @since 3.6.0
 2170     */
 2171    public static List<Method> getCommandMethods(Class<?> cls, String methodName) {
 2172        Set<Method> candidates = new HashSet<Method>();
 2173        // traverse public member methods (excludes static/non-public, includes inherited)
 2174        candidates.addAll(Arrays.asList(Assert.notNull(cls, "class").getMethods()));
 2175        // traverse directly declared methods (includes static/non-public, excludes inherited)
 2176        candidates.addAll(Arrays.asList(Assert.notNull(cls, "class").getDeclaredMethods()));
 2177
 2178        List<Method> result = new ArrayList<Method>();
 2179        for (Method method : candidates) {
 2180            if (method.isAnnotationPresent(Command.class)) {
 2181                if (methodName == null || methodName.equals(method.getName())) { result.add(method); }
 2182            }
 2183        }
 2184        Collections.sort(result, new Comparator<Method>() {
 2185            public int compare(Method o1, Method o2) { return o1.getName().compareTo(o2.getName()); }
 2186        });
 2187        return result;
 2188    }
 2189
 2190    /**
 2191     * Registers the specified type converter for the specified class. When initializing fields annotated with
 2192     * {@link Option}, the field's type is used as a lookup key to find the associated type converter, and this
 2193     * type converter converts the original command line argument string value to the correct type.
 2194     * <p>
 2195     * Java 8 lambdas make it easy to register custom type converters:
 2196     * </p>
 2197     * <pre>
 2198     * commandLine.registerConverter(java.nio.file.Path.class, s -&gt; java.nio.file.Paths.get(s));
 2199     * commandLine.registerConverter(java.time.Duration.class, s -&gt; java.time.Duration.parse(s));</pre>
 2200     * <p>
 2201     * Built-in type converters are pre-registered for the following java 1.5 types:
 2202     * </p>
 2203     * <ul>
 2204     *   <li>all primitive types</li>
 2205     *   <li>all primitive wrapper types: Boolean, Byte, Character, Double, Float, Integer, Long, Short</li>
 2206     *   <li>any enum</li>
 2207     *   <li>java.io.File</li>
 2208     *   <li>java.math.BigDecimal</li>
 2209     *   <li>java.math.BigInteger</li>
 2210     *   <li>java.net.InetAddress</li>
 2211     *   <li>java.net.URI</li>
 2212     *   <li>java.net.URL</li>
 2213     *   <li>java.nio.charset.Charset</li>
 2214     *   <li>java.sql.Time</li>
 2215     *   <li>java.util.Date</li>
 2216     *   <li>java.util.UUID</li>
 2217     *   <li>java.util.regex.Pattern</li>
 2218     *   <li>StringBuilder</li>
 2219     *   <li>CharSequence</li>
 2220     *   <li>String</li>
 2221     * </ul>
 2222     * <p>The specified converter will be registered with this {@code CommandLine} and the full hierarchy of its
 2223     * subcommands and nested sub-subcommands <em>at the moment the converter is registered</em>. Subcommands added
 2224     * later will not have this converter added automatically. To ensure a custom type converter is available to all
 2225     * subcommands, register the type converter last, after adding subcommands.</p>
 2226     *
 2227     * @param cls the target class to convert parameter string values to
 2228     * @param converter the class capable of converting string values to the specified target type
 2229     * @param <K> the target type
 2230     * @return this CommandLine object, to allow method chaining
 2231     * @see #addSubcommand(String, Object)
 2232     */
 2233    public <K> CommandLine registerConverter(Class<K> cls, ITypeConverter<K> converter) {
 2234        interpreter.converterRegistry.put(Assert.notNull(cls, "class"), Assert.notNull(converter, "converter"));
 2235        for (CommandLine command : getCommandSpec().commands.values()) {
 2236            command.registerConverter(cls, converter);
 2237        }
 2238        return this;
 2239    }
 2240
 2241    /** Returns the String that separates option names from option values when parsing command line options.
 2242     * @return the String the parser uses to separate option names from option values
 2243     * @see ParserSpec#separator() */
 2244    public String getSeparator() { return getCommandSpec().parser().separator(); }
 2245
 2246    /** Sets the String the parser uses to separate option names from option values to the specified value.
 2247     * The separator may also be set declaratively with the {@link CommandLine.Command#separator()} annotation attribute.
 2248     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
 2249     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
 2250     * later will have the default setting. To ensure a setting is applied to all
 2251     * subcommands, call the setter last, after adding subcommands.</p>
 2252     * @param separator the String that separates option names from option values
 2253     * @see ParserSpec#separator(String)
 2254     * @return this {@code CommandLine} object, to allow method chaining */
 2255    public CommandLine setSeparator(String separator) {
 2256        getCommandSpec().parser().separator(Assert.notNull(separator, "separator"));
 2257        for (CommandLine command : getCommandSpec().subcommands().values()) {
 2258            command.setSeparator(separator);
 2259        }
 2260        return this;
 2261    }
 2262
 2263    /** Returns the ResourceBundle of this command or {@code null} if no resource bundle is set.
 2264     * @see Command#resourceBundle()
 2265     * @see CommandSpec#resourceBundle()
 2266     * @since 3.6 */
 2267    public ResourceBundle getResourceBundle() { return getCommandSpec().resourceBundle(); }
 2268
 2269    /** Sets the ResourceBundle containing usage help message strings.
 2270     * <p>The specified bundle will be registered with this {@code CommandLine} and the full hierarchy of its
 2271     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
 2272     * later will not be impacted. To ensure a setting is applied to all
 2273     * subcommands, call the setter last, after adding subcommands.</p>
 2274     * @param bundle the ResourceBundle containing usage help message strings
 2275     * @return this {@code CommandLine} object, to allow method chaining
 2276     * @see Command#resourceBundle()
 2277     * @see CommandSpec#resourceBundle(ResourceBundle)
 2278     * @since 3.6 */
 2279    public CommandLine setResourceBundle(ResourceBundle bundle) {
 2280        getCommandSpec().resourceBundle(bundle);
 2281        for (CommandLine command : getCommandSpec().subcommands().values()) {
 2282            command.getCommandSpec().resourceBundle(bundle);
 2283        }
 2284        return this;
 2285    }
 2286
 2287    /** Returns the maximum width of the usage help message. The default is 80.
 2288     * @see UsageMessageSpec#width() */
 2289    public int getUsageHelpWidth() { return getCommandSpec().usageMessage().width(); }
 2290
 2291    /** Sets the maximum width of the usage help message. Longer lines are wrapped.
 2292     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
 2293     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
 2294     * later will have the default setting. To ensure a setting is applied to all
 2295     * subcommands, call the setter last, after adding subcommands.</p>
 2296     * @param width the maximum width of the usage help message
 2297     * @see UsageMessageSpec#width(int)
 2298     * @return this {@code CommandLine} object, to allow method chaining */
 2299    public CommandLine setUsageHelpWidth(int width) {
 2300        getCommandSpec().usageMessage().width(width);
 2301        for (CommandLine command : getCommandSpec().subcommands().values()) {
 2302            command.setUsageHelpWidth(width);
 2303        }
 2304        return this;
 2305    }
 2306
 2307    /** Returns the command name (also called program name) displayed in the usage help synopsis.
 2308     * @return the command name (also called program name) displayed in the usage
 2309     * @see CommandSpec#name()
 2310     * @since 2.0 */
 2311    public String getCommandName() { return getCommandSpec().name(); }
 2312
 2313    /** Sets the command name (also called program name) displayed in the usage help synopsis to the specified value.
 2314     * Note that this method only modifies the usage help message, it does not impact parsing behaviour.
 2315     * The command name may also be set declaratively with the {@link CommandLine.Command#name()} annotation attribute.
 2316     * @param commandName command name (also called program name) displayed in the usage help synopsis
 2317     * @return this {@code CommandLine} object, to allow method chaining
 2318     * @see CommandSpec#name(String)
 2319     * @since 2.0 */
 2320    public CommandLine setCommandName(String commandName) {
 2321        getCommandSpec().name(Assert.notNull(commandName, "commandName"));
 2322        return this;
 2323    }
 2324
 2325    /** Returns whether arguments starting with {@code '@'} should be treated as the path to an argument file and its
 2326     * contents should be expanded into separate arguments for each line in the specified file.
 2327     * This property is {@code true} by default.
 2328     * @return whether "argument files" or {@code @files} should be expanded into their content
 2329     * @since 2.1 */
 2330    public boolean isExpandAtFiles() { return getCommandSpec().parser().expandAtFiles(); }
 2331
 2332    /** Sets whether arguments starting with {@code '@'} should be treated as the path to an argument file and its
 2333     * contents should be expanded into separate arguments for each line in the specified file. ({@code true} by default.)
 2334     * @param expandAtFiles whether "argument files" or {@code @files} should be expanded into their content
 2335     * @return this {@code CommandLine} object, to allow method chaining
 2336     * @since 2.1 */
 2337    public CommandLine setExpandAtFiles(boolean expandAtFiles) {
 2338        getCommandSpec().parser().expandAtFiles(expandAtFiles);
 2339        return this;
 2340    }
 2341
 2342    /** Returns the character that starts a single-line comment or {@code null} if all content of argument files should
 2343     * be interpreted as arguments (without comments).
 2344     * If specified, all characters from the comment character to the end of the line are ignored.
 2345     * @return the character that starts a single-line comment or {@code null}. The default is {@code '#'}.
 2346     * @since 3.5 */
 2347    public Character getAtFileCommentChar() { return getCommandSpec().parser().atFileCommentChar(); }
 2348
 2349    /** Sets the character that starts a single-line comment or {@code null} if all content of argument files should
 2350     * be interpreted as arguments (without comments).
 2351     * If specified, all characters from the comment character to the end of the line are ignored.
 2352     * @param atFileCommentChar the character that starts a single-line comment or {@code null}. The default is {@code '#'}.
 2353     * @return this {@code CommandLine} object, to allow method chaining
 2354     * @since 3.5 */
 2355    public CommandLine setAtFileCommentChar(Character atFileCommentChar) {
 2356        getCommandSpec().parser().atFileCommentChar(atFileCommentChar);
 2357        for (CommandLine command : getCommandSpec().subcommands().values()) {
 2358            command.setAtFileCommentChar(atFileCommentChar);
 2359        }
 2360        return this;
 2361    }
 2362
 2363    /** Returns whether to use a simplified argument file format that is compatible with JCommander.
 2364     * In this format, every line (except empty lines and comment lines)
 2365     * is interpreted as a single argument. Arguments containing whitespace do not need to be quoted.
 2366     * When system property {@code "picocli.useSimplifiedAtFiles"} is defined, the system property value overrides the programmatically set value.
 2367     * @return whether to use a simplified argument file format. The default is {@code false}.
 2368     * @since 3.9 */
 2369    public boolean isUseSimplifiedAtFiles() { return getCommandSpec().parser().useSimplifiedAtFiles(); }
 2370
 2371    /** Sets whether to use a simplified argument file format that is compatible with JCommander.
 2372     * In this format, every line (except empty lines and comment lines)
 2373     * is interpreted as a single argument. Arguments containing whitespace do not need to be quoted.
 2374     * When system property {@code "picocli.useSimplifiedAtFiles"} is defined, the system property value overrides the programmatically set value.
 2375     * @param simplifiedAtFiles whether to use a simplified argument file format. The default is {@code false}.
 2376     * @return this {@code CommandLine} object, to allow method chaining
 2377     * @since 3.9 */
 2378    public CommandLine setUseSimplifiedAtFiles(boolean simplifiedAtFiles) {
 2379        getCommandSpec().parser().useSimplifiedAtFiles(simplifiedAtFiles);
 2380        for (CommandLine command : getCommandSpec().subcommands().values()) {
 2381            command.setUseSimplifiedAtFiles(simplifiedAtFiles);
 2382        }
 2383        return this;
 2384    }
 2385    private static boolean empty(String str) { return str == null || str.trim().length() == 0; }
 2386    private static boolean empty(Object[] array) { return array == null || array.length == 0; }
 2387    private static String str(String[] arr, int i) { return (arr == null || arr.length <= i) ? "" : arr[i]; }
 2388    private static boolean isBoolean(Class<?> type) { return type == Boolean.class || type == Boolean.TYPE; }
 2389    private static CommandLine toCommandLine(Object obj, IFactory factory) { return obj instanceof CommandLine ? (CommandLine) obj : new CommandLine(obj, factory);}
 2390    private static boolean isMultiValue(Class<?> cls) { return cls.isArray() || Collection.class.isAssignableFrom(cls) || Map.class.isAssignableFrom(cls); }
 2391    private static String format(String formatString, Object... params) {
 2392        try {
 2393            return formatString == null ? "" : String.format(formatString, params);
 2394        } catch (IllegalFormatException ex) {
 2395            new Tracer().warn("Could not format '%s' (Underlying error: %s). " +
 2396                    "Using raw String: '%%n' format strings have not been replaced with newlines. " +
 2397                    "Please ensure to escape '%%' characters with another '%%'.%n", formatString, ex.getMessage());
 2398            return formatString;
 2399        }
 2400    }
 2401
 2402    private static class NoCompletionCandidates implements Iterable<String> {
 2403        public Iterator<String> iterator() { throw new UnsupportedOperationException(); }
 2404    }
 2405    /**
 2406     * <p>
 2407     * Annotate fields in your class with {@code @Option} and picocli will initialize these fields when matching
 2408     * arguments are specified on the command line. In the case of command methods (annotated with {@code @Command}),
 2409     * command options can be defined by annotating method parameters with {@code @Option}.
 2410     * </p><p>
 2411     * Command class example:
 2412     * </p>
 2413     * <pre>
 2414     * import static picocli.CommandLine.*;
 2415     *
 2416     * public class MyClass {
 2417     *     &#064;Parameters(description = "Any number of input files")
 2418     *     private List&lt;File&gt; files = new ArrayList&lt;File&gt;();
 2419     *
 2420     *     &#064;Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
 2421     *     private File outputFile;
 2422     *
 2423     *     &#064;Option(names = { "-v", "--verbose"}, description = "Verbose mode. Helpful for troubleshooting. Multiple -v options increase the verbosity.")
 2424     *     private boolean[] verbose;
 2425     *
 2426     *     &#064;Option(names = { "-h", "--help", "-?", "-help"}, usageHelp = true, description = "Display this help and exit")
 2427     *     private boolean help;
 2428     * }
 2429     * </pre>
 2430     * <p>
 2431     * A field cannot be annotated with both {@code @Parameters} and {@code @Option} or a
 2432     * {@code ParameterException} is thrown.
 2433     * </p>
 2434     */
 2435    @Retention(RetentionPolicy.RUNTIME)
 2436    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
 2437    public @interface Option {
 2438        /**
 2439         * One or more option names. At least one option name is required.
 2440         * <p>
 2441         * Different environments have different conventions for naming options, but usually options have a prefix
 2442         * that sets them apart from parameters.
 2443         * Picocli supports all of the below styles. The default separator is {@code '='}, but this can be configured.
 2444         * </p><p>
 2445         * <b>*nix</b>
 2446         * </p><p>
 2447         * In Unix and Linux, options have a short (single-character) name, a long name or both.
 2448         * Short options
 2449         * (<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02">POSIX
 2450         * style</a> are single-character and are preceded by the {@code '-'} character, e.g., {@code `-v'}.
 2451         * <a href="https://www.gnu.org/software/tar/manual/html_node/Long-Options.html">GNU-style</a> long
 2452         * (or <em>mnemonic</em>) options start with two dashes in a row, e.g., {@code `--file'}.
 2453         * </p><p>Picocli supports the POSIX convention that short options can be grouped, with the last option
 2454         * optionally taking a parameter, which may be attached to the option name or separated by a space or
 2455         * a {@code '='} character. The below examples are all equivalent:
 2456         * </p><pre>
 2457         * -xvfFILE
 2458         * -xvf FILE
 2459         * -xvf=FILE
 2460         * -xv --file FILE
 2461         * -xv --file=FILE
 2462         * -x -v --file FILE
 2463         * -x -v --file=FILE
 2464         * </pre><p>
 2465         * <b>DOS</b>
 2466         * </p><p>
 2467         * DOS options mostly have upper case single-character names and start with a single slash {@code '/'} character.
 2468         * Option parameters are separated by a {@code ':'} character. Options cannot be grouped together but
 2469         * must be specified separately. For example:
 2470         * </p><pre>
 2471         * DIR /S /A:D /T:C
 2472         * </pre><p>
 2473         * <b>PowerShell</b>
 2474         * </p><p>
 2475         * Windows PowerShell options generally are a word preceded by a single {@code '-'} character, e.g., {@code `-Help'}.
 2476         * Option parameters are separated by a space or by a {@code ':'} character.
 2477         * </p>
 2478         * @return one or more option names
 2479         */
 2480        String[] names();
 2481
 2482        /**
 2483         * Indicates whether this option is required. By default this is false.
 2484         * <p>If an option is required, but a user invokes the program without specifying the required option,
 2485         * a {@link MissingParameterException} is thrown from the {@link #parse(String...)} method.</p>
 2486         * <p>Required options that are part of a {@linkplain ArgGroup group} are required <em>within the group</em>, not required within the command:
 2487         * the group's {@linkplain ArgGroup#multiplicity() multiplicity} determines whether the group itself is required or optional.</p>
 2488         * @return whether this option is required
 2489         */
 2490        boolean required() default false;
 2491
 2492        /**
 2493         * Set {@code help=true} if this option should disable validation of the remaining arguments:
 2494         * If the {@code help} option is specified, no error message is generated for missing required options.
 2495         * <p>
 2496         * This attribute is useful for special options like help ({@code -h} and {@code --help} on unix,
 2497         * {@code -?} and {@code -Help} on Windows) or version ({@code -V} and {@code --version} on unix,
 2498         * {@code -Version} on Windows).
 2499         * </p>
 2500         * <p>
 2501         * Note that the {@link #parse(String...)} method will not print help documentation. It will only set
 2502         * the value of the annotated field. It is the responsibility of the caller to inspect the annotated fields
 2503         * and take the appropriate action.
 2504         * </p>
 2505         * @return whether this option disables validation of the other arguments
 2506         * @deprecated Use {@link #usageHelp()} and {@link #versionHelp()} instead. See {@link #printHelpIfRequested(List, PrintStream, CommandLine.Help.Ansi)}
 2507         */
 2508        @Deprecated boolean help() default false;
 2509
 2510        /**
 2511         * Set {@code usageHelp=true} for the {@code --help} option that triggers display of the usage help message.
 2512         * The <a href="http://picocli.info/#_printing_help_automatically">convenience methods</a> {@code Commandline.call},
 2513         * {@code Commandline.run}, and {@code Commandline.parseWithHandler(s)} will automatically print usage help
 2514         * when an option with {@code usageHelp=true} was specified on the command line.
 2515         * <p>
 2516         * By default, <em>all</em> options and positional parameters are included in the usage help message
 2517         * <em>except when explicitly marked {@linkplain #hidden() hidden}.</em>
 2518         * </p><p>
 2519         * If this option is specified on the command line, picocli will not validate the remaining arguments (so no "missing required
 2520         * option" errors) and the {@link CommandLine#isUsageHelpRequested()} method will return {@code true}.
 2521         * </p><p>
 2522         * Alternatively, consider annotating your command with {@linkplain Command#mixinStandardHelpOptions() @Command(mixinStandardHelpOptions = true)}.
 2523         * </p>
 2524         * @return whether this option allows the user to request usage help
 2525         * @since 0.9.8
 2526         * @see #hidden()
 2527         * @see #run(Runnable, String...)
 2528         * @see #call(Callable, String...)
 2529         * @see #parseWithHandler(IParseResultHandler2, String[])
 2530         * @see #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)
 2531         */
 2532        boolean usageHelp() default false;
 2533
 2534        /**
 2535         * Set {@code versionHelp=true} for the {@code --version} option that triggers display of the version information.
 2536         * The <a href="http://picocli.info/#_printing_help_automatically">convenience methods</a> {@code Commandline.call},
 2537         * {@code Commandline.run}, and {@code Commandline.parseWithHandler(s)} will automatically print version information
 2538         * when an option with {@code versionHelp=true} was specified on the command line.
 2539         * <p>
 2540         * The version information string is obtained from the command's {@linkplain Command#version() version} annotation
 2541         * or from the {@linkplain Command#versionProvider() version provider}.
 2542         * </p><p>
 2543         * If this option is specified on the command line, picocli will not validate the remaining arguments (so no "missing required
 2544         * option" errors) and the {@link CommandLine#isUsageHelpRequested()} method will return {@code true}.
 2545         * </p><p>
 2546         * Alternatively, consider annotating your command with {@linkplain Command#mixinStandardHelpOptions() @Command(mixinStandardHelpOptions = true)}.
 2547         * </p>
 2548         * @return whether this option allows the user to request version information
 2549         * @since 0.9.8
 2550         * @see #hidden()
 2551         * @see #run(Runnable, String...)
 2552         * @see #call(Callable, String...)
 2553         * @see #parseWithHandler(IParseResultHandler2, String[])
 2554         * @see #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)
 2555         */
 2556        boolean versionHelp() default false;
 2557
 2558        /**
 2559         * Description of this option, used when generating the usage documentation. Each element of the array is rendered on a separate line.
 2560         * <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 %}.
 2561         * </p><p>
 2562         * The description may contain variables that are rendered when help is requested.
 2563         * The string {@code ${DEFAULT-VALUE}} is replaced with the default value of the option. This is regardless of
 2564         * the command's {@link Command#showDefaultValues() showDefaultValues} setting or the option's {@link #showDefaultValue() showDefaultValue} setting.
 2565         * The string {@code ${COMPLETION-CANDIDATES}} is replaced with the completion candidates generated by
 2566         * {@link #completionCandidates()} in the description for this option.
 2567         * Also, embedded {@code %n} newline markers are converted to actual newlines.
 2568         * </p>
 2569         * @return the description of this option
 2570         */
 2571        String[] description() default {};
 2572
 2573        /**
 2574         * Specifies the minimum number of required parameters and the maximum number of accepted parameters.
 2575         * If an option declares a positive arity, and the user specifies an insufficient number of parameters on the
 2576         * command line, a {@link MissingParameterException} is thrown by the {@link #parse(String...)} method.
 2577         * <p>
 2578         * In many cases picocli can deduce the number of required parameters from the field's type.
 2579         * By default, flags (boolean options) have arity zero,
 2580         * and single-valued type fields (String, int, Integer, double, Double, File, Date, etc) have arity one.
 2581         * Generally, fields with types that cannot hold multiple values can omit the {@code arity} attribute.
 2582         * </p><p>
 2583         * Fields used to capture options with arity two or higher should have a type that can hold multiple values,
 2584         * like arrays or Collections. See {@link #type()} for strongly-typed Collection fields.
 2585         * </p><p>
 2586         * For example, if an option has 2 required parameters and any number of optional parameters,
 2587         * specify {@code @Option(names = "-example", arity = "2..*")}.
 2588         * </p>
 2589         * <b>A note on boolean options</b>
 2590         * <p>
 2591         * By default picocli does not expect boolean options (also called "flags" or "switches") to have a parameter.
 2592         * You can make a boolean option take a required parameter by annotating your field with {@code arity="1"}.
 2593         * For example: </p>
 2594         * <pre>&#064;Option(names = "-v", arity = "1") boolean verbose;</pre>
 2595         * <p>
 2596         * Because this boolean field is defined with arity 1, the user must specify either {@code <program> -v false}
 2597         * or {@code <program> -v true}
 2598         * on the command line, or a {@link MissingParameterException} is thrown by the {@link #parse(String...)}
 2599         * method.
 2600         * </p><p>
 2601         * To make the boolean parameter possible but optional, define the field with {@code arity = "0..1"}.
 2602         * For example: </p>
 2603         * <pre>&#064;Option(names="-v", arity="0..1") boolean verbose;</pre>
 2604         * <p>This will accept any of the below without throwing an exception:</p>
 2605         * <pre>
 2606         * -v
 2607         * -v true
 2608         * -v false
 2609         * </pre>
 2610         * @return how many arguments this option requires
 2611         */
 2612        String arity() default "";
 2613
 2614        /**
 2615         * Specify a {@code paramLabel} for the option parameter to be used in the usage help message. If omitted,
 2616         * picocli uses the field name in fish brackets ({@code '<'} and {@code '>'}) by default. Example:
 2617         * <pre>class Example {
 2618         *     &#064;Option(names = {"-o", "--output"}, paramLabel="FILE", description="path of the output file")
 2619         *     private File out;
 2620         *     &#064;Option(names = {"-j", "--jobs"}, arity="0..1", description="Allow N jobs at once; infinite jobs with no arg.")
 2621         *     private int maxJobs = -1;
 2622         * }</pre>
 2623         * <p>By default, the above gives a usage help message like the following:</p><pre>
 2624         * Usage: &lt;main class&gt; [OPTIONS]
 2625         * -o, --output FILE       path of the output file
 2626         * -j, --jobs [&lt;maxJobs&gt;]  Allow N jobs at once; infinite jobs with no arg.
 2627         * </pre>
 2628         * @return name of the option parameter used in the usage help message
 2629         */
 2630        String paramLabel() default "";
 2631
 2632        /** Returns whether usage syntax decorations around the {@linkplain #paramLabel() paramLabel} should be suppressed.
 2633         * The default is {@code false}: by default, the paramLabel is surrounded with {@code '['} and {@code ']'} characters
 2634         * if the value is optional and followed by ellipses ("...") when multiple values can be specified.
 2635         * @since 3.6.0 */
 2636        boolean hideParamSyntax() default false;
 2637
 2638        /** <p>
 2639         * Optionally specify a {@code type} to control exactly what Class the option parameter should be converted
 2640         * to. This may be useful when the field type is an interface or an abstract class. For example, a field can
 2641         * be declared to have type {@code java.lang.Number}, and annotating {@code @Option(type=Short.class)}
 2642         * ensures that the option parameter value is converted to a {@code Short} before setting the field value.
 2643         * </p><p>
 2644         * For array fields whose <em>component</em> type is an interface or abstract class, specify the concrete <em>component</em> type.
 2645         * For example, a field with type {@code Number[]} may be annotated with {@code @Option(type=Short.class)}
 2646         * to ensure that option parameter values are converted to {@code Short} before adding an element to the array.
 2647         * </p><p>
 2648         * Picocli will use the {@link ITypeConverter} that is
 2649         * {@linkplain #registerConverter(Class, ITypeConverter) registered} for the specified type to convert
 2650         * the raw String values before modifying the field value.
 2651         * </p><p>
 2652         * Prior to 2.0, the {@code type} attribute was necessary for {@code Collection} and {@code Map} fields,
 2653         * but starting from 2.0 picocli will infer the component type from the generic type's type arguments.
 2654         * For example, for a field of type {@code Map<TimeUnit, Long>} picocli will know the option parameter
 2655         * should be split up in key=value pairs, where the key should be converted to a {@code java.util.concurrent.TimeUnit}
 2656         * enum value, and the value should be converted to a {@code Long}. No {@code @Option(type=...)} type attribute
 2657         * is required for this. For generic types with wildcards, picocli will take the specified upper or lower bound
 2658         * as the Class to convert to, unless the {@code @Option} annotation specifies an explicit {@code type} attribute.
 2659         * </p><p>
 2660         * If the field type is a raw collection or a raw map, and you want it to contain other values than Strings,
 2661         * or if the generic type's type arguments are interfaces or abstract classes, you may
 2662         * specify a {@code type} attribute to control the Class that the option parameter should be converted to.
 2663         * @return the type(s) to convert the raw String values
 2664         */
 2665        Class<?>[] type() default {};
 2666
 2667        /**
 2668         * Optionally specify one or more {@link ITypeConverter} classes to use to convert the command line argument into
 2669         * a strongly typed value (or key-value pair for map fields). This is useful when a particular field should
 2670         * use a custom conversion that is different from the normal conversion for the field's type.
 2671         * <p>For example, for a specific field you may want to use a converter that maps the constant names defined
 2672         * in {@link java.sql.Types java.sql.Types} to the {@code int} value of these constants, but any other {@code int} fields should
 2673         * not be affected by this and should continue to use the standard int converter that parses numeric values.</p>
 2674         * @return the type converter(s) to use to convert String values to strongly typed values for this field
 2675         * @see CommandLine#registerConverter(Class, ITypeConverter)
 2676         */
 2677        Class<? extends ITypeConverter<?>>[] converter() default {};
 2678
 2679        /**
 2680         * Specify a regular expression to use to split option parameter values before applying them to the field.
 2681         * All elements resulting from the split are added to the array or Collection. Ignored for single-value fields.
 2682         * @return a regular expression to split option parameter values or {@code ""} if the value should not be split
 2683         * @see String#split(String)
 2684         */
 2685        String split() default "";
 2686
 2687        /**
 2688         * Set {@code hidden=true} if this option should not be included in the usage help message.
 2689         * @return whether this option should be excluded from the usage documentation
 2690         */
 2691        boolean hidden() default false;
 2692
 2693        /** Returns the default value of this option, before splitting and type conversion.
 2694         * @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
 2695         * @since 3.2 */
 2696        String defaultValue() default "__no_default_value__";
 2697
 2698        /** Use this attribute to control for a specific option whether its default value should be shown in the usage
 2699         * help message. If not specified, the default value is only shown when the {@link Command#showDefaultValues()}
 2700         * is set {@code true} on the command. Use this attribute to specify whether the default value
 2701         * for this specific option should always be shown or never be shown, regardless of the command setting.
 2702         * <p>Note that picocli 3.2 allows {@linkplain #description() embedding default values} anywhere in the description that ignores this setting.</p>
 2703         * @return whether this option's default value should be shown in the usage help message
 2704         */
 2705        Help.Visibility showDefaultValue() default Help.Visibility.ON_DEMAND;
 2706
 2707        /** Use this attribute to specify an {@code Iterable<String>} class that generates completion candidates for this option.
 2708         * For map fields, completion candidates should be in {@code key=value} form.
 2709         * <p>
 2710         * Completion candidates are used in bash completion scripts generated by the {@code picocli.AutoComplete} class.
 2711         * Bash has special completion options to generate file names and host names, and the bash completion scripts
 2712         * generated by {@code AutoComplete} delegate to these bash built-ins for {@code @Options} whose {@code type} is
 2713         * {@code java.io.File}, {@code java.nio.file.Path} or {@code java.net.InetAddress}.
 2714         * </p><p>
 2715         * For {@code @Options} whose {@code type} is a Java {@code enum}, {@code AutoComplete} can generate completion
 2716         * candidates from the type. For other types, use this attribute to specify completion candidates.
 2717         * </p>
 2718         *
 2719         * @return a class whose instances can iterate over the completion candidates for this option
 2720         * @see picocli.CommandLine.IFactory
 2721         * @since 3.2 */
 2722        Class<? extends Iterable<String>> completionCandidates() default NoCompletionCandidates.class;
 2723
 2724        /**
 2725         * Set {@code interactive=true} if this option will prompt the end user for a value (like a password).
 2726         * Only supported for single-value options (not arrays, collections or maps).
 2727         * 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.
 2728         * @return whether this option prompts the end user for a value to be entered on the command line
 2729         * @since 3.5
 2730         */
 2731        boolean interactive() default false;
 2732
 2733        /** ResourceBundle key for this option. If not specified, (and a ResourceBundle {@linkplain Command#resourceBundle() exists for this command}) an attempt
 2734         * is made to find the option description using any of the option names (without leading hyphens) as key.
 2735         * @see OptionSpec#description()
 2736         * @since 3.6
 2737         */
 2738        String descriptionKey() default "";
 2739
 2740        /**
 2741         * 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.
 2742         * @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.
 2743         * @since 3.9
 2744         */
 2745        int order() default -1;
 2746
 2747        /**
 2748         * Specify the name of one or more options that this option is mutually exclusive with.
 2749         * Picocli will internally create a mutually exclusive {@linkplain ArgGroup group} with all specified options (and
 2750         * any options that the specified options are mutually exclusive with).
 2751         * <p>
 2752         * Options cannot be part of multiple groups to avoid ambiguity for the parser. Constructions
 2753         * where an option is part of multiple groups must be simplified so that the option is in just one group.
 2754         * For example: {@code (-a | -b) | (-a -x)} can be simplified to {@code (-a [-x] | -b)}.
 2755         * </p>
 2756         * @return the name or names of the option(s) that this option is mutually exclusive with.
 2757         * @since 4.0
 2758         */
 2759        String[] excludes() default {};
 2760
 2761        /**
 2762         * Specify the name of one or more options that this option must co-occur with.
 2763         * Picocli will internally create a co-occurring {@linkplain ArgGroup group} with all specified options (and
 2764         * any options that the specified options must co-occur with).
 2765         * <p>
 2766         * Options cannot be part of multiple groups to avoid ambiguity for the parser. Constructions
 2767         * where an option is part of multiple groups must be simplified so that the option is in just one group.
 2768         * For example: {@code (-a -x) | (-a -y)} can be simplified to {@code (-a [-x | -y])}.
 2769         * </p>
 2770         * @return the name or names of the option(s) that this option must co-occur with.
 2771         * @since 4.0
 2772         */
 2773        String[] needs() default {};
 2774    }
 2775    /**
 2776     * <p>
 2777     * Fields annotated with {@code @Parameters} will be initialized with positional parameters. By specifying the
 2778     * {@link #index()} attribute you can pick the exact position or a range of positional parameters to apply. If no
 2779     * index is specified, the field will get all positional parameters (and so it should be an array or a collection).
 2780     * </p><p>
 2781     * In the case of command methods (annotated with {@code @Command}), method parameters may be annotated with {@code @Parameters},
 2782     * but are are considered positional parameters by default, unless they are annotated with {@code @Option}.
 2783     * </p><p>
 2784     * Command class example:
 2785     * </p>
 2786     * <pre>
 2787     * import static picocli.CommandLine.*;
 2788     *
 2789     * public class MyCalcParameters {
 2790     *     &#064;Parameters(description = "Any number of input numbers")
 2791     *     private List&lt;BigDecimal&gt; files = new ArrayList&lt;BigDecimal&gt;();
 2792     *
 2793     *     &#064;Option(names = { "-h", "--help" }, usageHelp = true, description = "Display this help and exit")
 2794     *     private boolean help;
 2795     * }
 2796     * </pre><p>
 2797     * A field cannot be annotated with both {@code @Parameters} and {@code @Option} or a {@code ParameterException}
 2798     * is thrown.</p>
 2799     */
 2800    @Retention(RetentionPolicy.RUNTIME)
 2801    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
 2802    public @interface Parameters {
 2803        /** Specify an index ("0", or "1", etc.) to pick which of the command line arguments should be assigned to this
 2804         * field. For array or Collection fields, you can also specify an index range ("0..3", or "2..*", etc.) to assign
 2805         * a subset of the command line arguments to this field. The default is "*", meaning all command line arguments.
 2806         * @return an index or range specifying which of the command line arguments should be assigned to this field
 2807         */
 2808        String index() default "";
 2809
 2810        /** Description of the parameter(s), used when generating the usage documentation. Each element of the array is rendered on a separate line.
 2811         * <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 %}.
 2812         * </p><p>
 2813         * The description may contain variables that are rendered when help is requested.
 2814         * The string {@code ${DEFAULT-VALUE}} is replaced with the default value of the positional parameter. This is regardless of
 2815         * the command's {@link Command#showDefaultValues() showDefaultValues} setting or the positional parameter's {@link #showDefaultValue() showDefaultValue} setting.
 2816         * The string {@code ${COMPLETION-CANDIDATES}} is replaced with the completion candidates generated by
 2817         * {@link #completionCandidates()} in the description for this positional parameter.
 2818         * Also, embedded {@code %n} newline markers are converted to actual newlines.
 2819         * </p>
 2820         * @return the description of the parameter(s)
 2821         */
 2822        String[] description() default {};
 2823
 2824        /**
 2825         * Specifies the minimum number of required parameters and the maximum number of accepted parameters. If a
 2826         * positive arity is declared, and the user specifies an insufficient number of parameters on the command line,
 2827         * {@link MissingParameterException} is thrown by the {@link #parse(String...)} method.
 2828         * <p>The default depends on the type of the parameter: booleans require no parameters, arrays and Collections
 2829         * accept zero to any number of parameters, and any other type accepts one parameter.</p>
 2830         * <p>For single-value parameters, setting {@code arity = "0..1"} makes a positional parameter optional, while setting {@code arity = "1"} makes it required.</p>
 2831         * <p>Required parameters that are part of a {@linkplain ArgGroup group} are required <em>within the group</em>, not required within the command:
 2832         * the group's {@linkplain ArgGroup#multiplicity() multiplicity} determines whether the group itself is required or optional.</p>
 2833         * @return the range of minimum and maximum parameters accepted by this command
 2834         */
 2835        String arity() default "";
 2836
 2837        /**
 2838         * Specify a {@code paramLabel} for the parameter to be used in the usage help message. If omitted,
 2839         * picocli uses the field name in fish brackets ({@code '<'} and {@code '>'}) by default. Example:
 2840         * <pre>class Example {
 2841         *     &#064;Parameters(paramLabel="FILE", description="path of the input FILE(s)")
 2842         *     private File[] inputFiles;
 2843         * }</pre>
 2844         * <p>By default, the above gives a usage help message like the following:</p><pre>
 2845         * Usage: &lt;main class&gt; [FILE...]
 2846         * [FILE...]       path of the input FILE(s)
 2847         * </pre>
 2848         * @return name of the positional parameter used in the usage help message
 2849         */
 2850        String paramLabel() default "";
 2851
 2852        /** Returns whether usage syntax decorations around the {@linkplain #paramLabel() paramLabel} should be suppressed.
 2853         * The default is {@code false}: by default, the paramLabel is surrounded with {@code '['} and {@code ']'} characters
 2854         * if the value is optional and followed by ellipses ("...") when multiple values can be specified.
 2855         * @since 3.6.0 */
 2856        boolean hideParamSyntax() default false;
 2857
 2858        /**
 2859         * <p>
 2860         * Optionally specify a {@code type} to control exactly what Class the positional parameter should be converted
 2861         * to. This may be useful when the field type is an interface or an abstract class. For example, a field can
 2862         * be declared to have type {@code java.lang.Number}, and annotating {@code @Parameters(type=Short.class)}
 2863         * ensures that the positional parameter value is converted to a {@code Short} before setting the field value.
 2864         * </p><p>
 2865         * For array fields whose <em>component</em> type is an interface or abstract class, specify the concrete <em>component</em> type.
 2866         * For example, a field with type {@code Number[]} may be annotated with {@code @Parameters(type=Short.class)}
 2867         * to ensure that positional parameter values are converted to {@code Short} before adding an element to the array.
 2868         * </p><p>
 2869         * Picocli will use the {@link ITypeConverter} that is
 2870         * {@linkplain #registerConverter(Class, ITypeConverter) registered} for the specified type to convert
 2871         * the raw String values before modifying the field value.
 2872         * </p><p>
 2873         * Prior to 2.0, the {@code type} attribute was necessary for {@code Collection} and {@code Map} fields,
 2874         * but starting from 2.0 picocli will infer the component type from the generic type's type arguments.
 2875         * For example, for a field of type {@code Map<TimeUnit, Long>} picocli will know the positional parameter
 2876         * should be split up in key=value pairs, where the key should be converted to a {@code java.util.concurrent.TimeUnit}
 2877         * enum value, and the value should be converted to a {@code Long}. No {@code @Parameters(type=...)} type attribute
 2878         * is required for this. For generic types with wildcards, picocli will take the specified upper or lower bound
 2879         * as the Class to convert to, unless the {@code @Parameters} annotation specifies an explicit {@code type} attribute.
 2880         * </p><p>
 2881         * If the field type is a raw collection or a raw map, and you want it to contain other values than Strings,
 2882         * or if the generic type's type arguments are interfaces or abstract classes, you may
 2883         * specify a {@code type} attribute to control the Class that the positional parameter should be converted to.
 2884         * @return the type(s) to convert the raw String values
 2885         */
 2886        Class<?>[] type() default {};
 2887
 2888        /**
 2889         * Optionally specify one or more {@link ITypeConverter} classes to use to convert the command line argument into
 2890         * a strongly typed value (or key-value pair for map fields). This is useful when a particular field should
 2891         * use a custom conversion that is different from the normal conversion for the field's type.
 2892         * <p>For example, for a specific field you may want to use a converter that maps the constant names defined
 2893         * in {@link java.sql.Types java.sql.Types} to the {@code int} value of these constants, but any other {@code int} fields should
 2894         * not be affected by this and should continue to use the standard int converter that parses numeric values.</p>
 2895         * @return the type converter(s) to use to convert String values to strongly typed values for this field
 2896         * @see CommandLine#registerConverter(Class, ITypeConverter)
 2897         */
 2898        Class<? extends ITypeConverter<?>>[] converter() default {};
 2899
 2900        /**
 2901         * Specify a regular expression to use to split positional parameter values before applying them to the field.
 2902         * All elements resulting from the split are added to the array or Collection. Ignored for single-value fields.
 2903         * @return a regular expression to split operand values or {@code ""} if the value should not be split
 2904         * @see String#split(String)
 2905         */
 2906        String split() default "";
 2907
 2908        /**
 2909         * Set {@code hidden=true} if this parameter should not be included in the usage message.
 2910         * @return whether this parameter should be excluded from the usage message
 2911         */
 2912        boolean hidden() default false;
 2913
 2914        /** Returns the default value of this positional parameter, before splitting and type conversion.
 2915         * @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
 2916         * @since 3.2 */
 2917        String defaultValue() default "__no_default_value__";
 2918
 2919        /** Use this attribute to control for a specific positional parameter whether its default value should be shown in the usage
 2920         * help message. If not specified, the default value is only shown when the {@link Command#showDefaultValues()}
 2921         * is set {@code true} on the command. Use this attribute to specify whether the default value
 2922         * for this specific positional parameter should always be shown or never be shown, regardless of the command setting.
 2923         * <p>Note that picocli 3.2 allows {@linkplain #description() embedding default values} anywhere in the description that ignores this setting.</p>
 2924         * @return whether this positional parameter's default value should be shown in the usage help message
 2925         */
 2926        Help.Visibility showDefaultValue() default Help.Visibility.ON_DEMAND;
 2927
 2928        /** Use this attribute to specify an {@code Iterable<String>} class that generates completion candidates for
 2929         * this positional parameter. For map fields, completion candidates should be in {@code key=value} form.
 2930         * <p>
 2931         * Completion candidates are used in bash completion scripts generated by the {@code picocli.AutoComplete} class.
 2932         * Unfortunately, {@code picocli.AutoComplete} is not very good yet at generating completions for positional parameters.
 2933         * </p>
 2934         *
 2935         * @return a class whose instances can iterate over the completion candidates for this positional parameter
 2936         * @see picocli.CommandLine.IFactory
 2937         * @since 3.2 */
 2938        Class<? extends Iterable<String>> completionCandidates() default NoCompletionCandidates.class;
 2939
 2940        /**
 2941         * Set {@code interactive=true} if this positional parameter will prompt the end user for a value (like a password).
 2942         * Only supported for single-value positional parameters (not arrays, collections or maps).
 2943         * 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.
 2944         * @return whether this positional parameter prompts the end user for a value to be entered on the command line
 2945         * @since 3.5
 2946         */
 2947        boolean interactive() default false;
 2948
 2949        /** ResourceBundle key for this option. If not specified, (and a ResourceBundle {@linkplain Command#resourceBundle() exists for this command}) an attempt
 2950         * is made to find the positional parameter description using {@code paramLabel() + "[" + index() + "]"} as key.
 2951         *
 2952         * @see PositionalParamSpec#description()
 2953         * @since 3.6
 2954         */
 2955        String descriptionKey() default "";
 2956
 2957        /**
 2958         * Specify the name of one or more options that this positional parameter is mutually exclusive with.
 2959         * Picocli will internally create a mutually exclusive {@linkplain ArgGroup group} with all specified options (and
 2960         * any options and positional parameters that the specified options are mutually exclusive with).
 2961         * <p>
 2962         * An option or positional parameter cannot be part of multiple groups to avoid ambiguity for the parser. Constructions
 2963         * where an option is part of multiple groups must be simplified so that the option is in just one group.
 2964         * For example: {@code (-a | -b) | (-a -x)} can be simplified to {@code (-a [-x] | -b)}.
 2965         * </p>
 2966         * @return the name or names of the option(s) that this positional parameter is mutually exclusive with.
 2967         * @since 4.0
 2968         */
 2969        String[] excludes() default {};
 2970
 2971        /**
 2972         * Specify the name of one or more options that this option must co-occur with.
 2973         * Picocli will internally create a co-occurring {@linkplain ArgGroup group} with all specified options (and
 2974         * any options that the specified options must co-occur with).
 2975         * <p>
 2976         * Options cannot be part of multiple groups to avoid ambiguity for the parser. Constructions
 2977         * where an option is part of multiple groups must be simplified so that the option is in just one group.
 2978         * For example: {@code (-a -x) | (-a -y)} can be simplified to {@code (-a [-x | -y])}.
 2979         * </p>
 2980         * @return the name or names of the option(s) that this option must co-occur with.
 2981         * @since 4.0
 2982         */
 2983        String[] needs() default {};
 2984    }
 2985
 2986    /**
 2987     * <p>
 2988     * Fields annotated with {@code @ParentCommand} will be initialized with the parent command of the current subcommand.
 2989     * If the current command does not have a parent command, this annotation has no effect.
 2990     * </p><p>
 2991     * Parent commands often define options that apply to all the subcommands.
 2992     * This annotation offers a convenient way to inject a reference to the parent command into a subcommand, so the
 2993     * subcommand can access its parent options. For example:
 2994     * </p><pre>
 2995     * &#064;Command(name = "top", subcommands = Sub.class)
 2996     * class Top implements Runnable {
 2997     *
 2998     *     &#064;Option(names = {"-d", "--directory"}, description = "this option applies to all subcommands")
 2999     *     File baseDirectory;
 3000     *
 3001     *     public void run() { System.out.println("Hello from top"); }
 3002     * }
 3003     *
 3004     * &#064;Command(name = "sub")
 3005     * class Sub implements Runnable {
 3006     *
 3007     *     &#064;ParentCommand
 3008     *     private Top parent;
 3009     *
 3010     *     public void run() {
 3011     *         System.out.println("Subcommand: parent command 'directory' is " + parent.baseDirectory);
 3012     *     }
 3013     * }
 3014     * </pre>
 3015     * @since 2.2
 3016     */
 3017    @Retention(RetentionPolicy.RUNTIME)
 3018    @Target(ElementType.FIELD)
 3019    public @interface ParentCommand { }
 3020
 3021    /**
 3022     * Fields annotated with {@code @Unmatched} will be initialized with the list of unmatched command line arguments, if any.
 3023     * If this annotation is found, picocli automatically sets {@linkplain CommandLine#setUnmatchedArgumentsAllowed(boolean) unmatchedArgumentsAllowed} to {@code true}.
 3024     * @see CommandLine#isUnmatchedArgumentsAllowed()
 3025     * @since 3.0
 3026     */
 3027    @Retention(RetentionPolicy.RUNTIME)
 3028    @Target(ElementType.FIELD)
 3029    public @interface Unmatched { }
 3030
 3031    /**
 3032     * <p>
 3033     * Fields annotated with {@code @Mixin} are "expanded" into the current command: {@link Option @Option} and
 3034     * {@link Parameters @Parameters} in the mixin class are added to the options and positional parameters of this command.
 3035     * A {@link DuplicateOptionAnnotationsException} is thrown if any of the options in the mixin has the same name as
 3036     * an option in this command.
 3037     * </p><p>
 3038     * The {@code Mixin} annotation provides a way to reuse common options and parameters without subclassing. For example:
 3039     * </p><pre>
 3040     * class HelloWorld implements Runnable {
 3041     *
 3042     *     // adds the --help and --version options to this command
 3043     *     &#064;Mixin
 3044     *     private HelpOptions = new HelpOptions();
 3045     *
 3046     *     &#064;Option(names = {"-u", "--userName"}, required = true, description = "The user name")
 3047     *     String userName;
 3048     *
 3049     *     public void run() { System.out.println("Hello, " + userName); }
 3050     * }
 3051     *
 3052     * // Common reusable help options.
 3053     * class HelpOptions {
 3054     *
 3055     *     &#064;Option(names = { "-h", "--help"}, usageHelp = true, description = "Display this help and exit")
 3056     *     private boolean help;
 3057     *
 3058     *     &#064;Option(names = { "-V", "--version"}, versionHelp = true, description = "Display version info and exit")
 3059     *     private boolean versionHelp;
 3060     * }
 3061     * </pre>
 3062     * @since 3.0
 3063     */
 3064    @Retention(RetentionPolicy.RUNTIME)
 3065    @Target({ElementType.FIELD, ElementType.PARAMETER})
 3066    public @interface Mixin {
 3067        /** Optionally specify a name that the mixin object can be retrieved with from the {@code CommandSpec}.
 3068         * If not specified the name of the annotated field is used.
 3069         * @return a String to register the mixin object with, or an empty String if the name of the annotated field should be used */
 3070        String name() default "";
 3071    }
 3072    /**
 3073     * Fields annotated with {@code @Spec} will be initialized with the {@code CommandSpec} for the command the field is part of. Example usage:
 3074     * <pre>
 3075     * class InjectSpecExample implements Runnable {
 3076     *     &#064;Spec CommandSpec commandSpec;
 3077     *     //...
 3078     *     public void run() {
 3079     *         // do something with the injected objects
 3080     *     }
 3081     * }
 3082     * </pre>
 3083     * @since 3.2
 3084     */
 3085    @Retention(RetentionPolicy.RUNTIME)
 3086    @Target({ElementType.FIELD, ElementType.METHOD})
 3087    public @interface Spec { }
 3088    /**
 3089     * <p>Annotate your class with {@code @Command} when you want more control over the format of the generated help
 3090     * message. From 3.6, methods can also be annotated with {@code @Command}, where the method parameters define the
 3091     * command options and positional parameters.
 3092     * </p><pre>
 3093     * &#064;Command(name      = "Encrypt", mixinStandardHelpOptions = true,
 3094     *        description = "Encrypt FILE(s), or standard input, to standard output or to the output file.",
 3095     *        version     = "Encrypt version 1.0",
 3096     *        footer      = "Copyright (c) 2017")
 3097     * public class Encrypt {
 3098     *     &#064;Parameters(paramLabel = "FILE", description = "Any number of input files")
 3099     *     private List&lt;File&gt; files = new ArrayList&lt;File&gt;();
 3100     *
 3101     *     &#064;Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
 3102     *     private File outputFile;
 3103     *
 3104     *     &#064;Option(names = { "-v", "--verbose"}, description = "Verbose mode. Helpful for troubleshooting. Multiple -v options increase the verbosity.")
 3105     *     private boolean[] verbose;
 3106     * }</pre>
 3107     * <p>
 3108     * The structure of a help message looks like this:
 3109     * </p><ul>
 3110     *   <li>[header]</li>
 3111     *   <li>[synopsis]: {@code Usage: <commandName> [OPTIONS] [FILE...]}</li>
 3112     *   <li>[description]</li>
 3113     *   <li>[parameter list]: {@code      [FILE...]   Any number of input files}</li>
 3114     *   <li>[option list]: {@code   -h, --help   prints this help message and exits}</li>
 3115     *   <li>[footer]</li>
 3116     * </ul> */
 3117    @Retention(RetentionPolicy.RUNTIME)
 3118    @Target({ElementType.TYPE, ElementType.LOCAL_VARIABLE, ElementType.FIELD, ElementType.PACKAGE, ElementType.METHOD})
 3119    public @interface Command {
 3120        /** Program name to show in the synopsis. If omitted, {@code "<main class>"} is used.
 3121         * For {@linkplain #subcommands() declaratively added} subcommands, this attribute is also used
 3122         * by the parser to recognize subcommands in the command line arguments.
 3123         * @return the program name to show in the synopsis
 3124         * @see CommandSpec#name()
 3125         * @see Help#commandName() */
 3126        String name() default "<main class>";
 3127
 3128        /** Alternative command names by which this subcommand is recognized on the command line.
 3129         * @return one or more alternative command names
 3130         * @since 3.1 */
 3131        String[] aliases() default {};
 3132
 3133        /** A list of classes to instantiate and register as subcommands. When registering subcommands declaratively
 3134         * like this, you don't need to call the {@link CommandLine#addSubcommand(String, Object)} method. For example, this:
 3135         * <pre>
 3136         * &#064;Command(subcommands = {
 3137         *         GitStatus.class,
 3138         *         GitCommit.class,
 3139         *         GitBranch.class })
 3140         * public class Git { ... }
 3141         *
 3142         * CommandLine commandLine = new CommandLine(new Git());
 3143         * </pre> is equivalent to this:
 3144         * <pre>
 3145         * // alternative: programmatically add subcommands.
 3146         * // NOTE: in this case there should be no `subcommands` attribute on the @Command annotation.
 3147         * &#064;Command public class Git { ... }
 3148         *
 3149         * CommandLine commandLine = new CommandLine(new Git())
 3150         *         .addSubcommand("status",   new GitStatus())
 3151         *         .addSubcommand("commit",   new GitCommit())
 3152         *         .addSubcommand("branch",   new GitBranch());
 3153         * </pre>
 3154         * @return the declaratively registered subcommands of this command, or an empty array if none
 3155         * @see CommandLine#addSubcommand(String, Object)
 3156         * @see HelpCommand
 3157         * @since 0.9.8
 3158         */
 3159        Class<?>[] subcommands() default {};
 3160
 3161        /** Specify whether methods annotated with {@code @Command} should be registered as subcommands of their
 3162         * enclosing {@code @Command} class.
 3163         * The default is {@code true}. For example:
 3164         * <pre>
 3165         * &#064;Command
 3166         * public class Git {
 3167         *     &#064;Command
 3168         *     void status() { ... }
 3169         * }
 3170         *
 3171         * CommandLine git = new CommandLine(new Git());
 3172         * </pre> is equivalent to this:
 3173         * <pre>
 3174         * // don't add command methods as subcommands automatically
 3175         * &#064;Command(addMethodSubcommands = false)
 3176         * public class Git {
 3177         *     &#064;Command
 3178         *     void status() { ... }
 3179         * }
 3180         *
 3181         * // add command methods as subcommands programmatically
 3182         * CommandLine git = new CommandLine(new Git());
 3183         * CommandLine status = new CommandLine(CommandLine.getCommandMethods(Git.class, "status").get(0));
 3184         * git.addSubcommand("status", status);
 3185         * </pre>
 3186         * @return whether methods annotated with {@code @Command} should be registered as subcommands
 3187         * @see CommandLine#addSubcommand(String, Object)
 3188         * @see CommandLine#getCommandMethods(Class, String)
 3189         * @see CommandSpec#addMethodSubcommands()
 3190         * @since 3.6.0 */
 3191        boolean addMethodSubcommands() default true;
 3192
 3193        /** String that separates options from option parameters. Default is {@code "="}. Spaces are also accepted.
 3194         * @return the string that separates options from option parameters, used both when parsing and when generating usage help
 3195         * @see CommandLine#setSeparator(String) */
 3196        String separator() default "=";
 3197
 3198        /** Version information for this command, to print to the console when the user specifies an
 3199         * {@linkplain Option#versionHelp() option} to request version help. Each element of the array is rendered on a separate line.
 3200         * <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>
 3201         * <p>This is not part of the usage help message.</p>
 3202         *
 3203         * @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).
 3204         * @since 0.9.8
 3205         * @see CommandLine#printVersionHelp(PrintStream)
 3206         */
 3207        String[] version() default {};
 3208
 3209        /** Class that can provide version information dynamically at runtime. An implementation may return version
 3210         * information obtained from the JAR manifest, a properties file or some other source.
 3211         * @return a Class that can provide version information dynamically at runtime
 3212         * @since 2.2 */
 3213        Class<? extends IVersionProvider> versionProvider() default NoVersionProvider.class;
 3214
 3215        /**
 3216         * Adds the standard {@code -h} and {@code --help} {@linkplain Option#usageHelp() usageHelp} options and {@code -V}
 3217         * and {@code --version} {@linkplain Option#versionHelp() versionHelp} options to the options of this command.
 3218         * <p>
 3219         * Note that if no {@link #version()} or {@link #versionProvider()} is specified, the {@code --version} option will not print anything.
 3220         * </p><p>
 3221         * For {@linkplain #resourceBundle() internationalization}: the help option has {@code descriptionKey = "mixinStandardHelpOptions.help"},
 3222         * and the version option has {@code descriptionKey = "mixinStandardHelpOptions.version"}.
 3223         * </p>
 3224         * @return whether the auto-help mixin should be added to this command
 3225         * @since 3.0 */
 3226        boolean mixinStandardHelpOptions() default false;
 3227
 3228        /** Set this attribute to {@code true} if this subcommand is a help command, and required options and positional
 3229         * parameters of the parent command should not be validated. If a subcommand marked as {@code helpCommand} is
 3230         * specified on the command line, picocli will not validate the parent arguments (so no "missing required
 3231         * option" errors) and the {@link CommandLine#printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)} method will return {@code true}.
 3232         * @return {@code true} if this subcommand is a help command and picocli should not check for missing required
 3233         *      options and positional parameters on the parent command
 3234         * @since 3.0 */
 3235        boolean helpCommand() default false;
 3236
 3237        /** Set the heading preceding the header section.
 3238         * <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>
 3239         * @return the heading preceding the header section
 3240         * @see UsageMessageSpec#headerHeading()
 3241         * @see Help#headerHeading(Object...)  */
 3242        String headerHeading() default "";
 3243
 3244        /** Optional summary description of the command, shown before the synopsis. Each element of the array is rendered on a separate line.
 3245         * <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>
 3246         * @return summary description of the command
 3247         * @see UsageMessageSpec#header()
 3248         * @see Help#header(Object...)  */
 3249        String[] header() default {};
 3250
 3251        /** Set the heading preceding the synopsis text. The default heading is {@code "Usage: "} (without a line break between the heading and the synopsis text).
 3252         * <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>
 3253         * @return the heading preceding the synopsis text
 3254         * @see Help#synopsisHeading(Object...)  */
 3255        String synopsisHeading() default "Usage: ";
 3256
 3257        /** Specify {@code true} to generate an abbreviated synopsis like {@code "<main> [OPTIONS] [PARAMETERS...]"}.
 3258         * By default, a detailed synopsis with individual option names and parameters is generated.
 3259         * @return whether the synopsis should be abbreviated
 3260         * @see Help#abbreviatedSynopsis()
 3261         * @see Help#detailedSynopsis(Comparator, boolean) */
 3262        boolean abbreviateSynopsis() default false;
 3263
 3264        /** 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.
 3265         * <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>
 3266         * @return custom synopsis text to replace the auto-generated synopsis
 3267         * @see Help#customSynopsis(Object...) */
 3268        String[] customSynopsis() default {};
 3269
 3270        /** Set the heading preceding the description section.
 3271         * <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>
 3272         * @return the heading preceding the description section
 3273         * @see Help#descriptionHeading(Object...)  */
 3274        String descriptionHeading() default "";
 3275
 3276        /** 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.
 3277         * <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>
 3278         * @return description of this command
 3279         * @see Help#description(Object...) */
 3280        String[] description() default {};
 3281
 3282        /** Set the heading preceding the parameters list.
 3283         * <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>
 3284         * @return the heading preceding the parameters list
 3285         * @see Help#parameterListHeading(Object...)  */
 3286        String parameterListHeading() default "";
 3287
 3288        /** Set the heading preceding the options list.
 3289         * <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>
 3290         * @return the heading preceding the options list
 3291         * @see Help#optionListHeading(Object...)  */
 3292        String optionListHeading() default "";
 3293
 3294        /** Specify {@code false} to show Options in declaration order. The default is to sort alphabetically.
 3295         * @return whether options should be shown in alphabetic order. */
 3296        boolean sortOptions() default true;
 3297
 3298        /** Prefix required options with this character in the options list. The default is no marker: the synopsis
 3299         * indicates which options and parameters are required.
 3300         * @return the character to show in the options list to mark required options */
 3301        char requiredOptionMarker() default ' ';
 3302
 3303        /** Class that can provide default values dynamically at runtime. An implementation may return default
 3304         * value obtained from a configuration file like a properties file or some other source.
 3305         * @return a Class that can provide default values dynamically at runtime
 3306         * @since 3.6 */
 3307        Class<? extends IDefaultValueProvider> defaultValueProvider() default NoDefaultProvider.class;
 3308
 3309        /** Specify {@code true} to show default values in the description column of the options list (except for
 3310         * boolean options). False by default.
 3311         * <p>Note that picocli 3.2 allows {@linkplain Option#description() embedding default values} anywhere in the
 3312         * option or positional parameter description that ignores this setting.</p>
 3313         * @return whether the default values for options and parameters should be shown in the description column */
 3314        boolean showDefaultValues() default false;
 3315
 3316        /** Set the heading preceding the subcommands list. The default heading is {@code "Commands:%n"} (with a line break at the end).
 3317         * <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>
 3318         * @return the heading preceding the subcommands list
 3319         * @see Help#commandListHeading(Object...)  */
 3320        String commandListHeading() default "Commands:%n";
 3321
 3322        /** Set the heading preceding the footer section.
 3323         * <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>
 3324         * @return the heading preceding the footer section
 3325         * @see Help#footerHeading(Object...)  */
 3326        String footerHeading() default "";
 3327
 3328        /** Optional text to display after the list of options. Each element of the array is rendered on a separate line.
 3329         * <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>
 3330         * @return text to display after the list of options
 3331         * @see Help#footer(Object...) */
 3332        String[] footer() default {};
 3333
 3334        /**
 3335         * Set {@code hidden=true} if this command should not be included in the list of commands in the usage help of the parent command.
 3336         * @return whether this command should be excluded from the usage message
 3337         * @since 3.0
 3338         */
 3339        boolean hidden() default false;
 3340
 3341        /** Set the base name of the ResourceBundle to find option and positional parameters descriptions, as well as
 3342         * usage help message sections and section headings. <p>See {@link Messages} for more details and an example.</p>
 3343         * @return the base name of the ResourceBundle for usage help strings
 3344         * @see ArgSpec#messages()
 3345         * @see UsageMessageSpec#messages()
 3346         * @see CommandSpec#resourceBundle()
 3347         * @see CommandLine#setResourceBundle(ResourceBundle)
 3348         * @since 3.6
 3349         */
 3350        String resourceBundle() default "";
 3351
 3352        /** Set the {@link UsageMessageSpec#width(int) usage help message width}. The default is 80.
 3353         * @since 3.7
 3354         */
 3355        int usageHelpWidth() default 80;
 3356    }
 3357    /** A {@code Command} may define one or more {@code ArgGroups}: a group of options, positional parameters or a mixture of the two.
 3358     * Groups can be used to:
 3359     * <ul>
 3360     *     <li>define <b>mutually exclusive</b> arguments. By default, options and positional parameters
 3361     *     in a group are mutually exclusive. This can be controlled with the {@link #exclusive() exclusive} attribute.
 3362     *     Picocli will throw a {@link MutuallyExclusiveArgsException} if the command line contains multiple arguments that are mutually exclusive.</li>
 3363     *     <li>define a set of arguments that <b>must co-occur</b>. Set {@link #exclusive() exclusive = false}
 3364     *     to define a group of options and positional parameters that must always be specified together.
 3365     *     Picocli will throw a {@link MissingParameterException MissingParameterException} if not all the options and positional parameters in a co-occurring group are specified together.</li>
 3366     *     <li>create an <b>option section</b> in the usage help message.
 3367     *     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}).
 3368     *     Groups without a heading are only used for validation.
 3369     *     Set {@link #validate() validate = false} for groups whose purpose is only to customize the usage help message.</li>
 3370     *     <li>define <b>composite repeating argument groups</b>. Groups may contain other groups to create composite groups.</li>
 3371     * </ul>
 3372     * <p>Groups may be optional ({@code multiplicity = "0..1"}), required ({@code multiplicity = "1"}), or repeating groups ({@code multiplicity = "0..*"} or {@code multiplicity = "1..*"}).
 3373     * 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.
 3374     * For a group of co-occurring arguments, all arguments in the group must appear on the command line.
 3375     * </p>
 3376     * <p>Groups can be composed for validation purposes:</p>
 3377     * <ul>
 3378     * <li>When the parent group is mutually exclusive, only one of the subgroups may be present.</li>
 3379     * <li>When the parent group is a co-occurring group, all subgroups must be present.</li>
 3380     * <li>When the parent group is required, at least one subgroup must be present.</li>
 3381     * </ul>
 3382     * <p>
 3383     * Below is an example of an {@code ArgGroup} defining a set of dependent options that must occur together.
 3384     * All options are required <em>within the group</em>, while the group itself is optional:</p>
 3385     * <pre>
 3386     * public class DependentOptions {
 3387     *     &#064;ArgGroup(exclusive = false, multiplicity = "0..1")
 3388     *     Dependent group;
 3389     *
 3390     *     static class Dependent {
 3391     *         &#064;Option(names = "-a", required = true) int a;
 3392     *         &#064;Option(names = "-b", required = true) int b;
 3393     *         &#064;Option(names = "-c", required = true) int c;
 3394     *     }
 3395     * }</pre>
 3396     * @see ArgGroupSpec
 3397     * @since 4.0 */
 3398    @Retention(RetentionPolicy.RUNTIME)
 3399    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
 3400    public @interface ArgGroup {
 3401        /** The heading of this group, used when generating the usage documentation.
 3402         * When neither a {@link #heading() heading} nor a {@link #headingKey() headingKey} are specified,
 3403         * this group is used for validation only and does not change the usage help message. */
 3404        String heading() default "__no_heading__";
 3405
 3406        /** ResourceBundle key for this group's usage help message section heading.
 3407         * When neither a {@link #heading() heading} nor a {@link #headingKey() headingKey} are specified,
 3408         * this group is used for validation only and does not change the usage help message. */
 3409        String headingKey() default "__no_heading_key__";
 3410        /** Determines whether this is a mutually exclusive group; {@code true} by default.
 3411         * If {@code false}, this is a co-occurring group. Ignored if {@link #validate()} is {@code false}. */
 3412        boolean exclusive() default true;
 3413        /** Determines how often this group can be specified on the command line; {@code "0..1"} (optional) by default.
 3414         * For a group of mutually exclusive arguments, making the group required {@code multiplicity = "1"} means that
 3415         * one of the arguments in the group must appear on the command line, or a MissingParameterException is thrown.
 3416         * For a group of co-occurring arguments, making the group required means that all arguments in the group must appear on the command line.
 3417         * Ignored if {@link #validate()} is {@code false}. */
 3418        String multiplicity() default "0..1";
 3419        /** Determines whether picocli should validate the rules of this group ({@code true} by default).
 3420         * For a mutually exclusive group validation means verifying that no more than one elements of the group is specified on the command line;
 3421         * for a co-ocurring group validation means verifying that all elements of the group are specified on the command line.
 3422         * Set {@link #validate() validate = false} for groups whose purpose is only to customize the usage help message.
 3423         * @see #multiplicity()
 3424         * @see #heading() */
 3425        boolean validate() default true;
 3426        /** Determines the position in the options list in the usage help message at which this group should be shown.
 3427         * Options with a lower number are shown before options with a higher number.
 3428         * This attribute is only honored if {@link UsageMessageSpec#sortOptions()} is {@code false} for this command.*/
 3429        int order() default -1;
 3430    }
 3431    /**
 3432     * <p>
 3433     * When parsing command line arguments and initializing
 3434     * fields annotated with {@link Option @Option} or {@link Parameters @Parameters},
 3435     * String values can be converted to any type for which a {@code ITypeConverter} is registered.
 3436     * </p><p>
 3437     * This interface defines the contract for classes that know how to convert a String into some domain object.
 3438     * Custom converters can be registered with the {@link #registerConverter(Class, ITypeConverter)} method.
 3439     * </p><p>
 3440     * Java 8 lambdas make it easy to register custom type converters:
 3441     * </p>
 3442     * <pre>
 3443     * commandLine.registerConverter(java.nio.file.Path.class, s -&gt; java.nio.file.Paths.get(s));
 3444     * commandLine.registerConverter(java.time.Duration.class, s -&gt; java.time.Duration.parse(s));</pre>
 3445     * <p>
 3446     * Built-in type converters are pre-registered for the following java 1.5 types:
 3447     * </p>
 3448     * <ul>
 3449     *   <li>all primitive types</li>
 3450     *   <li>all primitive wrapper types: Boolean, Byte, Character, Double, Float, Integer, Long, Short</li>
 3451     *   <li>any enum</li>
 3452     *   <li>java.io.File</li>
 3453     *   <li>java.math.BigDecimal</li>
 3454     *   <li>java.math.BigInteger</li>
 3455     *   <li>java.net.InetAddress</li>
 3456     *   <li>java.net.URI</li>
 3457     *   <li>java.net.URL</li>
 3458     *   <li>java.nio.charset.Charset</li>
 3459     *   <li>java.sql.Time</li>
 3460     *   <li>java.util.Date</li>
 3461     *   <li>java.util.UUID</li>
 3462     *   <li>java.util.regex.Pattern</li>
 3463     *   <li>StringBuilder</li>
 3464     *   <li>CharSequence</li>
 3465     *   <li>String</li>
 3466     * </ul>
 3467     * @param <K> the type of the object that is the result of the conversion
 3468     */
 3469    public interface ITypeConverter<K> {
 3470        /**
 3471         * Converts the specified command line argument value to some domain object.
 3472         * @param value the command line argument String value
 3473         * @return the resulting domain object
 3474         * @throws Exception an exception detailing what went wrong during the conversion
 3475         */
 3476        K convert(String value) throws Exception;
 3477    }
 3478
 3479    /**
 3480     * Provides version information for a command. Commands may configure a provider with the
 3481     * {@link Command#versionProvider()} annotation attribute.
 3482     * @since 2.2 */
 3483    public interface IVersionProvider {
 3484        /**
 3485         * Returns version information for a command.
 3486         * @return version information (each string in the array is displayed on a separate line)
 3487         * @throws Exception an exception detailing what went wrong when obtaining version information
 3488         */
 3489        String[] getVersion() throws Exception;
 3490    }
 3491    private static class NoVersionProvider implements IVersionProvider {
 3492        public String[] getVersion() throws Exception { throw new UnsupportedOperationException(); }
 3493    }
 3494
 3495    /**
 3496     * Provides default value for a command. Commands may configure a provider with the
 3497     * {@link Command#defaultValueProvider()} annotation attribute.
 3498     * @since 3.6 */
 3499    public interface IDefaultValueProvider {
 3500
 3501        /** Returns the default value for an option or positional parameter or {@code null}.
 3502        * The returned value is converted to the type of the option/positional parameter
 3503        * via the same type converter used when populating this option/positional
 3504        * parameter from a command line argument.
 3505        * @param argSpec the option or positional parameter, never {@code null}
 3506        * @return the default value for the option or positional parameter, or {@code null} if
 3507        *       this provider has no default value for the specified option or positional parameter
 3508        * @throws Exception when there was a problem obtaining the default value
 3509        */
 3510        String defaultValue(ArgSpec argSpec) throws Exception;
 3511    }
 3512    private static class NoDefaultProvider implements IDefaultValueProvider {
 3513        public String defaultValue(ArgSpec argSpec) { throw new UnsupportedOperationException(); }
 3514    }
 3515
 3516    /**
 3517     * Creates the {@link Help} instance used to render the usage help message.
 3518     * @since 3.9
 3519     */
 3520    public interface IHelpFactory {
 3521        /** Returns a {@code Help} instance to assist in rendering the usage help message
 3522         * @param commandSpec the command to create usage help for
 3523         * @param colorScheme the color scheme to use when rendering usage help
 3524         * @return a {@code Help} instance
 3525         */
 3526        Help create(CommandSpec commandSpec, Help.ColorScheme colorScheme);
 3527    }
 3528
 3529    private static class DefaultHelpFactory implements IHelpFactory {
 3530        public Help create(CommandSpec commandSpec, Help.ColorScheme colorScheme) {
 3531            return new Help(commandSpec, colorScheme);
 3532        }
 3533    }
 3534
 3535    /**
 3536     * Factory for instantiating classes that are registered declaratively with annotation attributes, like
 3537     * {@link Command#subcommands()}, {@link Option#converter()}, {@link Parameters#converter()} and {@link Command#versionProvider()}.
 3538     * <p>The default factory implementation simply creates a new instance of the specified class when {@link #create(Class)} is invoked.
 3539     * </p><p>
 3540     * You may provide a custom implementation of this interface.
 3541     * For example, a custom factory implementation could delegate to a dependency injection container that provides the requested instance.
 3542     * </p>
 3543     * @see picocli.CommandLine#CommandLine(Object, IFactory)
 3544     * @see #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 3545     * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 3546     * @since 2.2 */
 3547    public interface IFactory {
 3548        /**
 3549         * Returns an instance of the specified class.
 3550         * @param cls the class of the object to return
 3551         * @param <K> the type of the object to return
 3552         * @return the instance
 3553         * @throws Exception an exception detailing what went wrong when creating or obtaining the instance
 3554         */
 3555        <K> K create(Class<K> cls) throws Exception;
 3556    }
 3557    /** Returns a default {@link IFactory} implementation. Package-protected for testing purposes. */
 3558    static IFactory defaultFactory() { return new DefaultFactory(); }
 3559    private static class DefaultFactory implements IFactory {
 3560        public <T> T create(Class<T> cls) throws Exception {
 3561            if (cls.isInterface() && Collection.class.isAssignableFrom(cls)) {
 3562                if (List.class.isAssignableFrom(cls)) {
 3563                    return cls.cast(new ArrayList<Object>());
 3564                } else if (SortedSet.class.isAssignableFrom(cls)) {
 3565                    return cls.cast(new TreeSet<Object>());
 3566                } else if (Set.class.isAssignableFrom(cls)) {
 3567                    return cls.cast(new LinkedHashSet<Object>());
 3568                } else if (Queue.class.isAssignableFrom(cls)) {
 3569                    return cls.cast(new LinkedList<Object>()); // ArrayDeque is only available since 1.6
 3570                }
 3571                return cls.cast(new ArrayList<Object>());
 3572            }
 3573            if (Map.class.isAssignableFrom(cls)) {
 3574                try { // if it is an implementation class, instantiate it
 3575                    return cls.cast(cls.getDeclaredConstructor().newInstance());
 3576                } catch (Exception ignored) { }
 3577                return cls.cast(new LinkedHashMap<Object, Object>());
 3578            }
 3579            try {
 3580                return cls.newInstance();
 3581            } catch (Exception ex) {
 3582                Constructor<T> constructor = cls.getDeclaredConstructor();
 3583                constructor.setAccessible(true);
 3584                return constructor.newInstance();
 3585            }
 3586        }
 3587        private static ITypeConverter<?>[] createConverter(IFactory factory, Class<? extends ITypeConverter<?>>[] classes) {
 3588            ITypeConverter<?>[] result = new ITypeConverter<?>[classes.length];
 3589            for (int i = 0; i < classes.length; i++) { result[i] = create(factory, classes[i]); }
 3590            return result;
 3591        }
 3592        static IVersionProvider createVersionProvider(IFactory factory, Class<? extends IVersionProvider> cls) {
 3593            return create(factory, cls);
 3594        }
 3595        static IDefaultValueProvider createDefaultValueProvider(IFactory factory, Class<? extends IDefaultValueProvider> cls) {
 3596            return create(factory, cls);
 3597        }
 3598        static Iterable<String> createCompletionCandidates(IFactory factory, Class<? extends Iterable<String>> cls) {
 3599            return create(factory, cls);
 3600        }
 3601        static <T> T create(IFactory factory, Class<T> cls) {
 3602            try { return factory.create(cls); }
 3603            catch (Exception ex) { throw new InitializationException("Could not instantiate " + cls + ": " + ex, ex); }
 3604        }
 3605    }
 3606    /** Describes the number of parameters required and accepted by an option or a positional parameter.
 3607     * @since 0.9.7
 3608     */
 3609    public static class Range implements Comparable<Range> {
 3610        /** Required number of parameters for an option or positional parameter. */
 3611        public final int min;
 3612        /** Maximum accepted number of parameters for an option or positional parameter. */
 3613        public final int max;
 3614        public final boolean isVariable;
 3615        private final boolean isUnspecified;
 3616        private final String originalValue;
 3617
 3618        /** Constructs a new Range object with the specified parameters.
 3619         * @param min minimum number of required parameters
 3620         * @param max maximum number of allowed parameters (or Integer.MAX_VALUE if variable)
 3621         * @param variable {@code true} if any number or parameters is allowed, {@code false} otherwise
 3622         * @param unspecified {@code true} if no arity was specified on the option/parameter (value is based on type)
 3623         * @param originalValue the original value that was specified on the option or parameter
 3624         */
 3625        public Range(int min, int max, boolean variable, boolean unspecified, String originalValue) {
 3626            if (min < 0 || max < 0) { throw new InitializationException("Invalid negative range (min=" + min + ", max=" + max + ")"); }
 3627            if (min > max) { throw new InitializationException("Invalid range (min=" + min + ", max=" + max + ")"); }
 3628            this.min = min;
 3629            this.max = max;
 3630            this.isVariable = variable;
 3631            this.isUnspecified = unspecified;
 3632            this.originalValue = originalValue;
 3633        }
 3634        /** Returns a new {@code Range} based on the {@link Option#arity()} annotation on the specified field,
 3635         * or the field type's default arity if no arity was specified.
 3636         * @param field the field whose Option annotation to inspect
 3637         * @return a new {@code Range} based on the Option arity annotation on the specified field */
 3638        public static Range optionArity(Field field) { return optionArity(new TypedMember(field)); }
 3639        private static Range optionArity(IAnnotatedElement member) {
 3640            return member.isAnnotationPresent(Option.class)
 3641                    ? adjustForType(Range.valueOf(member.getAnnotation(Option.class).arity()), member)
 3642                    : new Range(0, 0, false, true, "0");
 3643        }
 3644        /** Returns a new {@code Range} based on the {@link Parameters#arity()} annotation on the specified field,
 3645         * or the field type's default arity if no arity was specified.
 3646         * @param field the field whose Parameters annotation to inspect
 3647         * @return a new {@code Range} based on the Parameters arity annotation on the specified field */
 3648        public static Range parameterArity(Field field) { return parameterArity(new TypedMember(field)); }
 3649        private static Range parameterArity(IAnnotatedElement member) {
 3650            if (member.isAnnotationPresent(Parameters.class)) {
 3651                return adjustForType(Range.valueOf(member.getAnnotation(Parameters.class).arity()), member);
 3652            } else {
 3653                return member.isMethodParameter()
 3654                        ? adjustForType(Range.valueOf(""), member)
 3655                        : new Range(0, 0, false, true, "0");
 3656            }
 3657        }
 3658        /** Returns a new {@code Range} based on the {@link Parameters#index()} annotation on the specified field.
 3659         * @param field the field whose Parameters annotation to inspect
 3660         * @return a new {@code Range} based on the Parameters index annotation on the specified field */
 3661        public static Range parameterIndex(Field field) { return parameterIndex(new TypedMember(field)); }
 3662        private static Range parameterIndex(IAnnotatedElement member) {
 3663            if (member.isAnnotationPresent(Parameters.class)) {
 3664                Range result = Range.valueOf(member.getAnnotation(Parameters.class).index());
 3665                if (!result.isUnspecified) { return result; }
 3666            }
 3667            if (member.isMethodParameter()) {
 3668                int min = member.getMethodParamPosition();
 3669                int max = member.isMultiValue() ? Integer.MAX_VALUE : min;
 3670                return new Range(min, max, member.isMultiValue(), false, "");
 3671            }
 3672            return Range.valueOf("*"); // the default
 3673        }
 3674        static Range adjustForType(Range result, IAnnotatedElement member) {
 3675            return result.isUnspecified ? defaultArity(member) : result;
 3676        }
 3677        /** Returns the default arity {@code Range}: for {@link Option options} this is 0 for booleans and 1 for
 3678         * other types, for {@link Parameters parameters} booleans have arity 0, arrays or Collections have
 3679         * arity "0..*", and other types have arity 1.
 3680         * @param field the field whose default arity to return
 3681         * @return a new {@code Range} indicating the default arity of the specified field
 3682         * @since 2.0 */
 3683        public static Range defaultArity(Field field) { return defaultArity(new TypedMember(field)); }
 3684        private static Range defaultArity(IAnnotatedElement member) {
 3685            ITypeInfo info = member.getTypeInfo();
 3686            if (member.isAnnotationPresent(Option.class)) {
 3687                boolean zeroArgs = info.isBoolean() || (info.isMultiValue() && info.getAuxiliaryTypeInfos().get(0).isBoolean());
 3688                return zeroArgs ? Range.valueOf("0").unspecified(true)
 3689                                : Range.valueOf("1").unspecified(true);
 3690            }
 3691            if (info.isMultiValue()) {
 3692                return Range.valueOf("0..1").unspecified(true);
 3693            }
 3694            return Range.valueOf("1").unspecified(true);// for single-valued fields (incl. boolean positional parameters)
 3695        }
 3696        /** Returns the default arity {@code Range} for {@link Option options}: booleans have arity 0, other types have arity 1.
 3697         * @param type the type whose default arity to return
 3698         * @return a new {@code Range} indicating the default arity of the specified type
 3699         * @deprecated use {@link #defaultArity(Field)} instead */
 3700        @Deprecated public static Range defaultArity(Class<?> type) {
 3701            return isBoolean(type) ? Range.valueOf("0").unspecified(true) : Range.valueOf("1").unspecified(true);
 3702        }
 3703        private int size() { return 1 + max - min; }
 3704        static Range parameterCapacity(IAnnotatedElement member) {
 3705            Range arity = parameterArity(member);
 3706            if (!member.isMultiValue()) { return arity; }
 3707            Range index = parameterIndex(member);
 3708            return parameterCapacity(arity, index);
 3709        }
 3710        private static Range parameterCapacity(Range arity, Range index) {
 3711            if (arity.max == 0)    { return arity; }
 3712            if (index.size() == 1) { return arity; }
 3713            if (index.isVariable)  { return Range.valueOf(arity.min + "..*"); }
 3714            if (arity.size() == 1) { return Range.valueOf(arity.min * index.size() + ""); }
 3715            if (arity.isVariable)  { return Range.valueOf(arity.min * index.size() + "..*"); }
 3716            return Range.valueOf(arity.min * index.size() + ".." + arity.max * index.size());
 3717        }
 3718
 3719        /** Leniently parses the specified String as an {@code Range} value and return the result. A range string can
 3720         * be a fixed integer value or a range of the form {@code MIN_VALUE + ".." + MAX_VALUE}. If the
 3721         * {@code MIN_VALUE} string is not numeric, the minimum is zero. If the {@code MAX_VALUE} is not numeric, the
 3722         * range is taken to be variable and the maximum is {@code Integer.MAX_VALUE}.
 3723         * @param range the value range string to parse
 3724         * @return a new {@code Range} value */
 3725        public static Range valueOf(String range) {
 3726            range = range.trim();
 3727            boolean unspecified = range.length() == 0 || range.startsWith(".."); // || range.endsWith("..");
 3728            int min = -1, max = -1;
 3729            boolean variable = false;
 3730            int dots = -1;
 3731            if ((dots = range.indexOf("..")) >= 0) {
 3732                min = parseInt(range.substring(0, dots), 0);
 3733                max = parseInt(range.substring(dots + 2), Integer.MAX_VALUE);
 3734                variable = max == Integer.MAX_VALUE;
 3735            } else {
 3736                max = parseInt(range, Integer.MAX_VALUE);
 3737                variable = max == Integer.MAX_VALUE;
 3738                min = variable ? 0 : max;
 3739            }
 3740            Range result = new Range(min, max, variable, unspecified, range);
 3741            return result;
 3742        }
 3743        private static int parseInt(String str, int defaultValue) {
 3744            try {
 3745                return Integer.parseInt(str);
 3746            } catch (Exception ex) {
 3747                return defaultValue;
 3748            }
 3749        }
 3750        /** Returns a new Range object with the {@code min} value replaced by the specified value.
 3751         * The {@code max} of the returned Range is guaranteed not to be less than the new {@code min} value.
 3752         * @param newMin the {@code min} value of the returned Range object
 3753         * @return a new Range object with the specified {@code min} value */
 3754        public Range min(int newMin) { return new Range(newMin, Math.max(newMin, max), isVariable, isUnspecified, originalValue); }
 3755
 3756        /** Returns a new Range object with the {@code max} value replaced by the specified value.
 3757         * The {@code min} of the returned Range is guaranteed not to be greater than the new {@code max} value.
 3758         * @param newMax the {@code max} value of the returned Range object
 3759         * @return a new Range object with the specified {@code max} value */
 3760        public Range max(int newMax) { return new Range(Math.min(min, newMax), newMax, isVariable, isUnspecified, originalValue); }
 3761
 3762        /** Returns a new Range object with the {@code isUnspecified} value replaced by the specified value.
 3763         * @param unspecified the {@code unspecified} value of the returned Range object
 3764         * @return a new Range object with the specified {@code unspecified} value */
 3765        public Range unspecified(boolean unspecified) { return new Range(min, max, isVariable, unspecified, originalValue); }
 3766        /** Returns {@code true} if this Range is a default value, {@code false} if the user specified this value.
 3767         * @since 4.0 */
 3768        public boolean isUnspecified() { return isUnspecified; }
 3769
 3770        /**
 3771         * Returns {@code true} if this Range includes the specified value, {@code false} otherwise.
 3772         * @param value the value to check
 3773         * @return {@code true} if the specified value is not less than the minimum and not greater than the maximum of this Range
 3774         */
 3775        public boolean contains(int value) { return min <= value && max >= value; }
 3776
 3777        public boolean equals(Object object) {
 3778            if (!(object instanceof Range)) { return false; }
 3779            Range other = (Range) object;
 3780            return other.max == this.max && other.min == this.min && other.isVariable == this.isVariable;
 3781        }
 3782        public int hashCode() {
 3783            return ((17 * 37 + max) * 37 + min) * 37 + (isVariable ? 1 : 0);
 3784        }
 3785        public String toString() {
 3786            return min == max ? String.valueOf(min) : min + ".." + (isVariable ? "*" : max);
 3787        }
 3788        public int compareTo(Range other) {
 3789            int result = min - other.min;
 3790            return (result == 0) ? max - other.max : result;
 3791        }
 3792
 3793        boolean overlaps(Range index) {
 3794            return contains(index.min) || contains(index.max) || index.contains(min) || index.contains(max);
 3795        }
 3796    }
 3797    private static void validatePositionalParameters(List<PositionalParamSpec> positionalParametersFields) {
 3798        int min = 0;
 3799        for (PositionalParamSpec positional : positionalParametersFields) {
 3800            Range index = positional.index();
 3801            if (index.min > min) {
 3802                throw new ParameterIndexGapException("Command definition should have a positional parameter with index=" + min +
 3803                        ". Nearest positional parameter '" + positional.paramLabel() + "' has index=" + index.min);
 3804            }
 3805            min = Math.max(min, index.max);
 3806            min = min == Integer.MAX_VALUE ? min : min + 1;
 3807        }
 3808    }
 3809    @SuppressWarnings("unchecked") private static Stack<String> copy(Stack<String> stack) { return (Stack<String>) stack.clone(); }
 3810    private static <T> Stack<T> reverse(Stack<T> stack) {
 3811        Collections.reverse(stack);
 3812        return stack;
 3813    }
 3814    private static <T> List<T> reverseList(List<T> list) {
 3815        Collections.reverse(list);
 3816        return list;
 3817    }
 3818
 3819    /** This class provides a namespace for classes and interfaces that model concepts and attributes of command line interfaces in picocli.
 3820     * @since 3.0 */
 3821    public static final class Model {
 3822        private Model() {}
 3823
 3824        /** The scope of a binding is the context where the current value should be gotten from or set to.
 3825         * For a field, the scope is the object whose field value to get/set. For a method binding, it is the
 3826         * object on which the method should be invoked.
 3827         * <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>
 3828         * @since 4.0
 3829         */
 3830        public interface IScope extends IGetter, ISetter {}
 3831
 3832        /** Customizable getter for obtaining the current value of an option or positional parameter.
 3833         * When an option or positional parameter is matched on the command line, its getter or setter is invoked to capture the value.
 3834         * For example, an option can be bound to a field or a method, and when the option is matched on the command line, the
 3835         * field's value is set or the method is invoked with the option parameter value.
 3836         * @since 3.0 */
 3837        public static interface IGetter {
 3838            /** Returns the current value of the binding. For multi-value options and positional parameters,
 3839             * this method returns an array, collection or map to add values to.
 3840             * @throws PicocliException if a problem occurred while obtaining the current value
 3841             * @throws Exception internally, picocli call sites will catch any exceptions thrown from here and rethrow them wrapped in a PicocliException */
 3842            <T> T get() throws Exception;
 3843        }
 3844        /** Customizable setter for modifying the value of an option or positional parameter.
 3845         * When an option or positional parameter is matched on the command line, its setter is invoked to capture the value.
 3846         * For example, an option can be bound to a field or a method, and when the option is matched on the command line, the
 3847         * field's value is set or the method is invoked with the option parameter value.
 3848         * @since 3.0 */
 3849        public static interface ISetter {
 3850            /** Sets the new value of the option or positional parameter.
 3851             *
 3852             * @param value the new value of the option or positional parameter
 3853             * @param <T> type of the value
 3854             * @return the previous value of the binding (if supported by this binding)
 3855             * @throws PicocliException if a problem occurred while setting the new value
 3856             * @throws Exception internally, picocli call sites will catch any exceptions thrown from here and rethrow them wrapped in a PicocliException */
 3857            <T> T set(T value) throws Exception;
 3858        }
 3859
 3860        /** The {@code CommandSpec} class models a command specification, including the options, positional parameters and subcommands
 3861         * supported by the command, as well as attributes for the version help message and the usage help message of the command.
 3862         * <p>
 3863         * Picocli views a command line application as a hierarchy of commands: there is a top-level command (usually the Java
 3864         * class with the {@code main} method) with optionally a set of command line options, positional parameters and subcommands.
 3865         * Subcommands themselves can have options, positional parameters and nested sub-subcommands to any level of depth.
 3866         * </p><p>
 3867         * The object model has a corresponding hierarchy of {@code CommandSpec} objects, each with a set of {@link OptionSpec},
 3868         * {@link PositionalParamSpec} and {@linkplain CommandLine subcommands} associated with it.
 3869         * This object model is used by the picocli command line interpreter and help message generator.
 3870         * </p><p>Picocli can construct a {@code CommandSpec} automatically from classes with {@link Command @Command}, {@link Option @Option} and
 3871         * {@link Parameters @Parameters} annotations. Alternatively a {@code CommandSpec} can be constructed programmatically.
 3872         * </p>
 3873         * @since 3.0 */
 3874        public static class CommandSpec {
 3875            /** Constant String holding the default program name: {@code "<main class>" }. */
 3876            static final String DEFAULT_COMMAND_NAME = "<main class>";
 3877
 3878            /** Constant Boolean holding the default setting for whether this is a help command: <code>{@value}</code>.*/
 3879            static final Boolean DEFAULT_IS_HELP_COMMAND = Boolean.FALSE;
 3880
 3881            /** Constant Boolean holding the default setting for whether method commands should be added as subcommands: <code>{@value}</code>.*/
 3882            static final Boolean DEFAULT_IS_ADD_METHOD_SUBCOMMANDS = Boolean.TRUE;
 3883
 3884            private final Map<String, CommandLine> commands = new LinkedHashMap<String, CommandLine>();
 3885            private final Map<String, OptionSpec> optionsByNameMap = new LinkedHashMap<String, OptionSpec>();
 3886            private final Map<Character, OptionSpec> posixOptionsByKeyMap = new LinkedHashMap<Character, OptionSpec>();
 3887            private final Map<String, CommandSpec> mixins = new LinkedHashMap<String, CommandSpec>();
 3888            private final List<ArgSpec> requiredArgs = new ArrayList<ArgSpec>();
 3889            private final List<ArgSpec> args = new ArrayList<ArgSpec>();
 3890            private final List<OptionSpec> options = new ArrayList<OptionSpec>();
 3891            private final List<PositionalParamSpec> positionalParameters = new ArrayList<PositionalParamSpec>();
 3892            private final List<UnmatchedArgsBinding> unmatchedArgs = new ArrayList<UnmatchedArgsBinding>();
 3893            private final List<ArgGroupSpec> groups = new ArrayList<ArgGroupSpec>();
 3894            private final ParserSpec parser = new ParserSpec();
 3895            private final UsageMessageSpec usageMessage = new UsageMessageSpec();
 3896
 3897            private final Object userObject;
 3898            private CommandLine commandLine;
 3899            private CommandSpec parent;
 3900            private Boolean isAddMethodSubcommands;
 3901
 3902            private String name;
 3903            private Set<String> aliases = new LinkedHashSet<String>();
 3904            private Boolean isHelpCommand;
 3905            private IVersionProvider versionProvider;
 3906            private IDefaultValueProvider defaultValueProvider;
 3907            private String[] version;
 3908            private String toString;
 3909
 3910            private CommandSpec(Object userObject) { this.userObject = userObject; }
 3911    
 3912            /** Creates and returns a new {@code CommandSpec} without any associated user object. */
 3913            public static CommandSpec create() { return wrapWithoutInspection(null); }
 3914    
 3915            /** Creates and returns a new {@code CommandSpec} with the specified associated user object.
 3916             * The specified user object is <em>not</em> inspected for annotations.
 3917             * @param userObject the associated user object. May be any object, may be {@code null}.
 3918             */
 3919            public static CommandSpec wrapWithoutInspection(Object userObject) { return new CommandSpec(userObject); }
 3920
 3921            /** Creates and returns a new {@code CommandSpec} initialized from the specified associated user object. The specified
 3922             * user object must have at least one {@link Command}, {@link Option} or {@link Parameters} annotation.
 3923             * @param userObject the user object annotated with {@link Command}, {@link Option} and/or {@link Parameters} annotations.
 3924             * @throws InitializationException if the specified object has no picocli annotations or has invalid annotations
 3925             */
 3926            public static CommandSpec forAnnotatedObject(Object userObject) { return forAnnotatedObject(userObject, new DefaultFactory()); }
 3927
 3928            /** Creates and returns a new {@code CommandSpec} initialized from the specified associated user object. The specified
 3929             * user object must have at least one {@link Command}, {@link Option} or {@link Parameters} annotation.
 3930             * @param userObject the user object annotated with {@link Command}, {@link Option} and/or {@link Parameters} annotations.
 3931             * @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
 3932             * @throws InitializationException if the specified object has no picocli annotations or has invalid annotations
 3933             */
 3934            public static CommandSpec forAnnotatedObject(Object userObject, IFactory factory) { return CommandReflection.extractCommandSpec(userObject, factory, true); }
 3935
 3936            /** Creates and returns a new {@code CommandSpec} initialized from the specified associated user object. If the specified
 3937             * user object has no {@link Command}, {@link Option} or {@link Parameters} annotations, an empty {@code CommandSpec} is returned.
 3938             * @param userObject the user object annotated with {@link Command}, {@link Option} and/or {@link Parameters} annotations.
 3939             * @throws InitializationException if the specified object has invalid annotations
 3940             */
 3941            public static CommandSpec forAnnotatedObjectLenient(Object userObject) { return forAnnotatedObjectLenient(userObject, new DefaultFactory()); }
 3942
 3943            /** Creates and returns a new {@code CommandSpec} initialized from the specified associated user object. If the specified
 3944             * user object has no {@link Command}, {@link Option} or {@link Parameters} annotations, an empty {@code CommandSpec} is returned.
 3945             * @param userObject the user object annotated with {@link Command}, {@link Option} and/or {@link Parameters} annotations.
 3946             * @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
 3947             * @throws InitializationException if the specified object has invalid annotations
 3948             */
 3949            public static CommandSpec forAnnotatedObjectLenient(Object userObject, IFactory factory) { return CommandReflection.extractCommandSpec(userObject, factory, false); }
 3950
 3951            /** Ensures all attributes of this {@code CommandSpec} have a valid value; throws an {@link InitializationException} if this cannot be achieved. */
 3952            void validate() {
 3953                Collections.sort(positionalParameters, new PositionalParametersSorter());
 3954                validatePositionalParameters(positionalParameters);
 3955                List<String> wrongUsageHelpAttr = new ArrayList<String>();
 3956                List<String> wrongVersionHelpAttr = new ArrayList<String>();
 3957                List<String> usageHelpAttr = new ArrayList<String>();
 3958                List<String> versionHelpAttr = new ArrayList<String>();
 3959                for (OptionSpec option : options()) {
 3960                    if (option.usageHelp()) {
 3961                        usageHelpAttr.add(option.longestName());
 3962                        if (!isBoolean(option.type())) { wrongUsageHelpAttr.add(option.longestName()); }
 3963                    }
 3964                    if (option.versionHelp()) {
 3965                        versionHelpAttr.add(option.longestName());
 3966                        if (!isBoolean(option.type())) { wrongVersionHelpAttr.add(option.longestName()); }
 3967                    }
 3968                }
 3969                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.";
 3970                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";
 3971                if (!wrongUsageHelpAttr.isEmpty()) {
 3972                    throw new InitializationException(String.format(wrongType, wrongUsageHelpAttr, "usageHelp", "--help", "usage help message"));
 3973                }
 3974                if (!wrongVersionHelpAttr.isEmpty()) {
 3975                    throw new InitializationException(String.format(wrongType, wrongVersionHelpAttr, "versionHelp", "--version", "version information"));
 3976                }
 3977                if (usageHelpAttr.size() > 1)   { new Tracer().warn(multiple, usageHelpAttr, "usageHelp", "--help", "usage help message"); }
 3978                if (versionHelpAttr.size() > 1) { new Tracer().warn(multiple, versionHelpAttr, "versionHelp", "--version", "version information"); }
 3979            }
 3980    
 3981            /** Returns the user object associated with this command.
 3982             * @see CommandLine#getCommand() */
 3983            public Object userObject() { return userObject; }
 3984    
 3985            /** Returns the CommandLine constructed with this {@code CommandSpec} model. */
 3986            public CommandLine commandLine() { return commandLine;}
 3987    
 3988            /** Sets the CommandLine constructed with this {@code CommandSpec} model. */
 3989            protected CommandSpec commandLine(CommandLine commandLine) {
 3990                this.commandLine = commandLine;
 3991                for (CommandSpec mixedInSpec : mixins.values()) {
 3992                    mixedInSpec.commandLine(commandLine);
 3993                }
 3994                for (CommandLine sub : commands.values()) {
 3995                    sub.getCommandSpec().parent(this);
 3996                }
 3997                return this;
 3998            }
 3999
 4000            /** Returns the parser specification for this command. */
 4001            public ParserSpec parser() { return parser; }
 4002            /** Initializes the parser specification for this command from the specified settings and returns this commandSpec.*/
 4003            public CommandSpec parser(ParserSpec settings) { parser.initFrom(settings); return this; }
 4004
 4005            /** Returns the usage help message specification for this command. */
 4006            public UsageMessageSpec usageMessage() { return usageMessage; }
 4007            /** Initializes the usageMessage specification for this command from the specified settings and returns this commandSpec.*/
 4008            public CommandSpec usageMessage(UsageMessageSpec settings) { usageMessage.initFrom(settings, this); return this; }
 4009
 4010            /** Returns the resource bundle base name for this command.
 4011             * @return the resource bundle base name from the {@linkplain UsageMessageSpec#messages()}
 4012             * @since 4.0 */
 4013            public String resourceBundleBaseName() { return Messages.resourceBundleBaseName(usageMessage.messages()); }
 4014            /** Initializes the resource bundle for this command: sets the {@link UsageMessageSpec#messages(Messages) UsageMessageSpec.messages} to
 4015             * a {@link Messages Messages} object created from this command spec and the specified bundle, and then sets the
 4016             * {@link ArgSpec#messages(Messages) ArgSpec.messages} of all options and positional parameters in this command
 4017             * to the same {@code Messages} instance. Subcommands are not modified.
 4018             * <p>This method is preferable to {@link #resourceBundle(ResourceBundle)} for pre-Java 8</p>
 4019             * @param resourceBundleBaseName the base name of the ResourceBundle to set, may be {@code null}
 4020             * @return this commandSpec
 4021             * @see #addSubcommand(String, CommandLine)
 4022             * @since 4.0 */
 4023            public CommandSpec resourceBundleBaseName(String resourceBundleBaseName) {
 4024                ResourceBundle bundle = empty(resourceBundleBaseName) ? null : ResourceBundle.getBundle(resourceBundleBaseName);
 4025                setBundle(resourceBundleBaseName, bundle);
 4026                return this;
 4027            }
 4028            /** Returns the resource bundle for this command.
 4029             * @return the resource bundle from the {@linkplain UsageMessageSpec#messages()}
 4030             * @since 3.6 */
 4031            public ResourceBundle resourceBundle() { return Messages.resourceBundle(usageMessage.messages()); }
 4032            /** Initializes the resource bundle for this command: sets the {@link UsageMessageSpec#messages(Messages) UsageMessageSpec.messages} to
 4033             * a {@link Messages Messages} object created from this command spec and the specified bundle, and then sets the
 4034             * {@link ArgSpec#messages(Messages) ArgSpec.messages} of all options and positional parameters in this command
 4035             * to the same {@code Messages} instance. Subcommands are not modified.
 4036             * @param bundle the ResourceBundle to set, may be {@code null}
 4037             * @return this commandSpec
 4038             * @see #addSubcommand(String, CommandLine)
 4039             * @since 3.6 */
 4040            public CommandSpec resourceBundle(ResourceBundle bundle) {
 4041                setBundle(Messages.extractName(bundle), bundle);
 4042                return this;
 4043            }
 4044            private void setBundle(String bundleBaseName, ResourceBundle bundle) {
 4045                usageMessage().messages(new Messages(this, bundleBaseName, bundle));
 4046                updateArgSpecMessages();
 4047            }
 4048            private void updateArgSpecMessages() {
 4049                for (OptionSpec opt : options()) { opt.messages(usageMessage().messages()); }
 4050                for (PositionalParamSpec pos : positionalParameters()) { pos.messages(usageMessage().messages()); }
 4051                for (ArgGroupSpec group : argGroups()) { group.messages(usageMessage().messages()); }
 4052            }
 4053
 4054            /** Returns a read-only view of the subcommand map. */
 4055            public Map<String, CommandLine> subcommands() { return Collections.unmodifiableMap(commands); }
 4056    
 4057            /** Adds the specified subcommand with the specified name.
 4058             * If the specified subcommand does not have a ResourceBundle set, it is initialized to the ResourceBundle of this command spec.
 4059             * @param name subcommand name - when this String is encountered in the command line arguments the subcommand is invoked
 4060             * @param subcommand describes the subcommand to envoke when the name is encountered on the command line
 4061             * @return this {@code CommandSpec} object for method chaining */
 4062            public CommandSpec addSubcommand(String name, CommandSpec subcommand) {
 4063                return addSubcommand(name, new CommandLine(subcommand));
 4064            }
 4065    
 4066            /** Adds the specified subcommand with the specified name.
 4067             * If the specified subcommand does not have a ResourceBundle set, it is initialized to the ResourceBundle of this command spec.
 4068             * @param name subcommand name - when this String is encountered in the command line arguments the subcommand is invoked
 4069             * @param subCommandLine the subcommand to envoke when the name is encountered on the command line
 4070             * @return this {@code CommandSpec} object for method chaining */
 4071            public CommandSpec addSubcommand(String name, CommandLine subCommandLine) {
 4072                Tracer t = new Tracer();
 4073                if (t.isDebug()) {t.debug("Adding subcommand '%s' to '%s'%n", name, this.qualifiedName());}
 4074                CommandLine previous = commands.put(name, subCommandLine);
 4075                if (previous != null && previous != subCommandLine) { throw new InitializationException("Another subcommand named '" + name + "' already exists for command '" + this.name() + "'"); }
 4076                CommandSpec subSpec = subCommandLine.getCommandSpec();
 4077                if (subSpec.name == null) { subSpec.name(name); }
 4078                subSpec.parent(this);
 4079                for (String alias : subSpec.aliases()) {
 4080                    if (t.isDebug()) {t.debug("Adding alias '%s' for subcommand '%s' to '%s'%n", alias, name, this.qualifiedName());}
 4081                    previous = commands.put(alias, subCommandLine);
 4082                    if (previous != null && previous != subCommandLine) { throw new InitializationException("Alias '" + alias + "' for subcommand '" + name + "' is already used by another subcommand of '" + this.name() + "'"); }
 4083                }
 4084                subSpec.initCommandHierarchyWithResourceBundle(resourceBundleBaseName(), resourceBundle());
 4085                return this;
 4086            }
 4087            private void initCommandHierarchyWithResourceBundle(String bundleBaseName, ResourceBundle rb) {
 4088                if (resourceBundle() == null) {
 4089                    setBundle(bundleBaseName, rb);
 4090                }
 4091                for (CommandLine sub : commands.values()) { // percolate down the hierarchy
 4092                    sub.getCommandSpec().initCommandHierarchyWithResourceBundle(bundleBaseName, rb);
 4093                }
 4094            }
 4095
 4096            /** Returns whether method commands should be added as subcommands. Used by the annotation processor.
 4097             * @since 4.0 */
 4098            public boolean isAddMethodSubcommands() { return (isAddMethodSubcommands == null) ? DEFAULT_IS_ADD_METHOD_SUBCOMMANDS : isAddMethodSubcommands; }
 4099            /** Sets whether method commands should be added as subcommands. Used by the annotation processor.
 4100             * @since 4.0 */
 4101            public CommandSpec setAddMethodSubcommands(Boolean addMethodSubcommands) { isAddMethodSubcommands = addMethodSubcommands; return this; }
 4102
 4103            /** Reflects on the class of the {@linkplain #userObject() user object} and registers any command methods
 4104             * (class methods annotated with {@code @Command}) as subcommands.
 4105             *
 4106             * @return this {@link CommandSpec} object for method chaining
 4107             * @see #addMethodSubcommands(IFactory)
 4108             * @see #addSubcommand(String, CommandLine)
 4109             * @since 3.6.0
 4110             */
 4111            public CommandSpec addMethodSubcommands() { return addMethodSubcommands(new DefaultFactory()); }
 4112
 4113            /** Reflects on the class of the {@linkplain #userObject() user object} and registers any command methods
 4114             * (class methods annotated with {@code @Command}) as subcommands.
 4115             * @param factory the factory used to create instances of subcommands, converters, etc., that are registered declaratively with annotation attributes
 4116             * @return this {@link CommandSpec} object for method chaining
 4117             * @see #addSubcommand(String, CommandLine)
 4118             * @since 3.7.0
 4119             */
 4120            public CommandSpec addMethodSubcommands(IFactory factory) {
 4121                if (userObject() instanceof Method) {
 4122                     throw new InitializationException("Cannot discover subcommand methods of this Command Method: " + userObject());
 4123                }
 4124                for (CommandLine sub : createMethodSubcommands(userObject().getClass(), factory)) {
 4125                    addSubcommand(sub.getCommandName(), sub);
 4126                }
 4127                isAddMethodSubcommands = true;
 4128                return this;
 4129            }
 4130            static List<CommandLine> createMethodSubcommands(Class<?> cls, IFactory factory) {
 4131                List<CommandLine> result = new ArrayList<CommandLine>();
 4132                for (Method method : getCommandMethods(cls, null)) {
 4133                    result.add(new CommandLine(method, factory));
 4134                }
 4135                return result;
 4136            }
 4137
 4138            /** Returns the parent command of this subcommand, or {@code null} if this is a top-level command. */
 4139            public CommandSpec parent() { return parent; }
 4140    
 4141            /** Sets the parent command of this subcommand.
 4142             * @return this CommandSpec for method chaining */
 4143            public CommandSpec parent(CommandSpec parent) { this.parent = parent; return this; }
 4144    
 4145            /** Adds the specified option spec or positional parameter spec to the list of configured arguments to expect.
 4146             * @param arg the option spec or positional parameter spec to add
 4147             * @return this CommandSpec for method chaining */
 4148            public CommandSpec add(ArgSpec arg) { return arg.isOption() ? addOption((OptionSpec) arg) : addPositional((PositionalParamSpec) arg); }
 4149    
 4150            /** Adds the specified option spec to the list of configured arguments to expect.
 4151             * The option's {@linkplain OptionSpec#description()} may now return Strings from this
 4152             * CommandSpec's {@linkplain UsageMessageSpec#messages() messages}.
 4153             * The option parameter's {@linkplain OptionSpec#defaultValueString()} may
 4154             * now return Strings from this CommandSpec's {@link CommandSpec#defaultValueProvider()} IDefaultValueProvider}.
 4155             * @param option the option spec to add
 4156             * @return this CommandSpec for method chaining
 4157             * @throws DuplicateOptionAnnotationsException if any of the names of the specified option is the same as the name of another option */
 4158            public CommandSpec addOption(OptionSpec option) {
 4159                for (String name : option.names()) { // cannot be null or empty
 4160                    OptionSpec existing = optionsByNameMap.put(name, option);
 4161                    if (existing != null) { /* was: && !existing.equals(option)) {*/ // since 4.0 ArgGroups: an option cannot be in multiple groups
 4162                        throw DuplicateOptionAnnotationsException.create(name, option, existing);
 4163                    }
 4164                    if (name.length() == 2 && name.startsWith("-")) { posixOptionsByKeyMap.put(name.charAt(1), option); }
 4165                }
 4166                options.add(option);
 4167                return addArg(option);
 4168            }
 4169            /** Adds the specified positional parameter spec to the list of configured arguments to expect.
 4170             * The positional parameter's {@linkplain PositionalParamSpec#description()} may
 4171             * now return Strings from this CommandSpec's {@linkplain UsageMessageSpec#messages() messages}.
 4172             * The positional parameter's {@linkplain PositionalParamSpec#defaultValueString()} may
 4173             * now return Strings from this CommandSpec's {@link CommandSpec#defaultValueProvider()} IDefaultValueProvider}.
 4174             * @param positional the positional parameter spec to add
 4175             * @return this CommandSpec for method chaining */
 4176            public CommandSpec addPositional(PositionalParamSpec positional) {
 4177                positionalParameters.add(positional);
 4178                return addArg(positional);
 4179            }
 4180            private CommandSpec addArg(ArgSpec arg) {
 4181                args.add(arg);
 4182                if (arg.required() && arg.group() == null) { requiredArgs.add(arg); }
 4183                arg.messages(usageMessage().messages());
 4184                arg.commandSpec = this;
 4185                return this;
 4186            }
 4187
 4188            /** Adds the specified {@linkplain ArgGroupSpec argument group} to the groups in this command.
 4189             * @param group the group spec to add
 4190             * @return this CommandSpec for method chaining
 4191             * @throws InitializationException if the specified group or one of its {@linkplain ArgGroupSpec#parentGroup() ancestors} has already been added
 4192             * @since 4.0 */
 4193            public CommandSpec addArgGroup(ArgGroupSpec group) {
 4194                Assert.notNull(group, "group");
 4195                if (group.parentGroup() != null) {
 4196                    throw new InitializationException("Groups that are part of another group should not be added to a command. Add only the top-level group.");
 4197                }
 4198                check(group, flatten(groups, new HashSet<ArgGroupSpec>()));
 4199                this.groups.add(group);
 4200                addGroupArgsToCommand(group, new HashMap<String, ArgGroupSpec>());
 4201                return this;
 4202            }
 4203            private void addGroupArgsToCommand(ArgGroupSpec group, Map<String, ArgGroupSpec> added) {
 4204                for (ArgSpec arg : group.args()) {
 4205                    if (arg.isOption()) {
 4206                        for (String name : ((OptionSpec) arg).names()) {
 4207                            if (added.containsKey(name)) {
 4208                                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)).");
 4209                            }
 4210                        }
 4211                        for (String name : ((OptionSpec) arg).names()) { added.put(name, group); }
 4212                    }
 4213                    add(arg);
 4214                }
 4215                for (ArgGroupSpec sub : group.subgroups()) { addGroupArgsToCommand(sub, added); }
 4216            }
 4217            private Set<ArgGroupSpec> flatten(Collection<ArgGroupSpec> groups, Set<ArgGroupSpec> result) {
 4218                for (ArgGroupSpec group : groups) { flatten(group, result); } return result;
 4219            }
 4220            private Set<ArgGroupSpec> flatten(ArgGroupSpec group, Set<ArgGroupSpec> result) {
 4221                result.add(group);
 4222                for (ArgGroupSpec sub : group.subgroups()) { flatten(sub, result); }
 4223                return result;
 4224            }
 4225            private void check(ArgGroupSpec group, Set<ArgGroupSpec> existing) {
 4226                if (existing.contains(group)) {
 4227                    throw new InitializationException("The specified group " + group.synopsis() + " has already been added to the " + qualifiedName() + " command.");
 4228                }
 4229                for (ArgGroupSpec sub : group.subgroups()) { check(sub, existing); }
 4230            }
 4231
 4232            /** Adds the specified mixin {@code CommandSpec} object to the map of mixins for this command.
 4233             * @param name the name that can be used to later retrieve the mixin
 4234             * @param mixin the mixin whose options and positional parameters and other attributes to add to this command
 4235             * @return this CommandSpec for method chaining */
 4236            public CommandSpec addMixin(String name, CommandSpec mixin) {
 4237                mixins.put(name, mixin);
 4238    
 4239                parser.initSeparator(mixin.parser.separator());
 4240                initName(mixin.name());
 4241                initVersion(mixin.version());
 4242                initHelpCommand(mixin.helpCommand());
 4243                initVersionProvider(mixin.versionProvider());
 4244                initDefaultValueProvider(mixin.defaultValueProvider());
 4245                usageMessage.initFromMixin(mixin.usageMessage, this);
 4246
 4247                for (Map.Entry<String, CommandLine> entry : mixin.subcommands().entrySet()) {
 4248                    addSubcommand(entry.getKey(), entry.getValue());
 4249                }
 4250                for (OptionSpec optionSpec         : mixin.options())              { addOption(optionSpec); }
 4251                for (PositionalParamSpec paramSpec : mixin.positionalParameters()) { addPositional(paramSpec); }
 4252                return this;
 4253            }
 4254
 4255            /** Adds the specified {@code UnmatchedArgsBinding} to the list of model objects to capture unmatched arguments for this command.
 4256             * @param spec the unmatched arguments binding to capture unmatched arguments
 4257             * @return this CommandSpec for method chaining */
 4258            public CommandSpec addUnmatchedArgsBinding(UnmatchedArgsBinding spec) { unmatchedArgs.add(spec); parser().unmatchedArgumentsAllowed(true); return this; }
 4259    
 4260            /** Returns a map of the mixin names to mixin {@code CommandSpec} objects configured for this command.
 4261             * @return an immutable map of mixins added to this command. */
 4262            public Map<String, CommandSpec> mixins() { return Collections.unmodifiableMap(mixins); }
 4263    
 4264            /** Returns the list of options configured for this command.
 4265             * @return an immutable list of options that this command recognizes. */
 4266            public List<OptionSpec> options() { return Collections.unmodifiableList(options); }
 4267    
 4268            /** Returns the list of positional parameters configured for this command.
 4269             * @return an immutable list of positional parameters that this command recognizes. */
 4270            public List<PositionalParamSpec> positionalParameters() { return Collections.unmodifiableList(positionalParameters); }
 4271
 4272            /** Returns the {@linkplain ArgGroupSpec argument groups} in this command.
 4273             * @return an immutable list of groups of options and positional parameters in this command
 4274             * @since 4.0 */
 4275            public List<ArgGroupSpec> argGroups() { return Collections.unmodifiableList(groups); }
 4276
 4277            /** Returns a map of the option names to option spec objects configured for this command.
 4278             * @return an immutable map of options that this command recognizes. */
 4279            public Map<String, OptionSpec> optionsMap() { return Collections.unmodifiableMap(optionsByNameMap); }
 4280    
 4281            /** Returns a map of the short (single character) option names to option spec objects configured for this command.
 4282             * @return an immutable map of options that this command recognizes. */
 4283            public Map<Character, OptionSpec> posixOptionsMap() { return Collections.unmodifiableMap(posixOptionsByKeyMap); }
 4284
 4285            /** Returns the list of required options and positional parameters configured for this command.
 4286             * This does not include options and positional parameters that are part of a {@linkplain ArgGroupSpec group}.
 4287             * @return an immutable list of the required options and positional parameters for this command. */
 4288            public List<ArgSpec> requiredArgs() { return Collections.unmodifiableList(requiredArgs); }
 4289
 4290            /** Returns the list of {@link UnmatchedArgsBinding UnmatchedArgumentsBindings} configured for this command;
 4291             * each {@code UnmatchedArgsBinding} captures the arguments that could not be matched to any options or positional parameters. */
 4292            public List<UnmatchedArgsBinding> unmatchedArgsBindings() { return Collections.unmodifiableList(unmatchedArgs); }
 4293    
 4294            /** Returns name of this command. Used in the synopsis line of the help message.
 4295             * {@link #DEFAULT_COMMAND_NAME} by default, initialized from {@link Command#name()} if defined.
 4296             * @see #qualifiedName() */
 4297            public String name() { return (name == null) ? DEFAULT_COMMAND_NAME : name; }
 4298
 4299            /** Returns the alias command names of this subcommand.
 4300             * @since 3.1 */
 4301            public String[] aliases() { return aliases.toArray(new String[0]); }
 4302
 4303            /** Returns all names of this command, including {@link #name()} and {@link #aliases()}.
 4304             * @since 3.9 */
 4305            public Set<String> names() {
 4306                Set<String> result = new LinkedHashSet<String>();
 4307                result.add(name());
 4308                result.addAll(Arrays.asList(aliases()));
 4309                return result;
 4310            }
 4311
 4312            /** Returns the list of all options and positional parameters configured for this command.
 4313             * @return an immutable list of all options and positional parameters for this command. */
 4314            public List<ArgSpec> args() { return Collections.unmodifiableList(args); }
 4315            Object[] argValues() {
 4316                Map<Class<?>, CommandSpec> allMixins = null;
 4317                int argsLength = args.size();
 4318                int shift = 0;
 4319                for (Map.Entry<String, CommandSpec> mixinEntry : mixins.entrySet()) {
 4320                    if (mixinEntry.getKey().equals(AutoHelpMixin.KEY)) {
 4321                        shift = 2;
 4322                        argsLength -= shift;
 4323                        continue;
 4324                    }
 4325                    CommandSpec mixin = mixinEntry.getValue();
 4326                    int mixinArgs = mixin.args.size();
 4327                    argsLength -= (mixinArgs - 1); // subtract 1 because that's the mixin
 4328                    if (allMixins == null) {
 4329                        allMixins = new IdentityHashMap<Class<?>, CommandSpec>(mixins.size());
 4330                    }
 4331                    allMixins.put(mixin.userObject.getClass(), mixin);
 4332                }
 4333
 4334                Object[] values = new Object[argsLength];
 4335                if (allMixins == null) {
 4336                    for (int i = 0; i < values.length; i++) { values[i] = args.get(i + shift).getValue(); }
 4337                } else {
 4338                    int argIndex = shift;
 4339                    Class<?>[] methodParams = ((Method) userObject).getParameterTypes();
 4340                    for (int i = 0; i < methodParams.length; i++) {
 4341                        final Class<?> param = methodParams[i];
 4342                        CommandSpec mixin = allMixins.remove(param);
 4343                        if (mixin == null) {
 4344                            values[i] = args.get(argIndex++).getValue();
 4345                        } else {
 4346                            values[i] = mixin.userObject;
 4347                            argIndex += mixin.args.size();
 4348                        }
 4349                    }
 4350                }
 4351                return values;
 4352            }
 4353
 4354            /** Returns the String to use as the program name in the synopsis line of the help message:
 4355             * this command's {@link #name() name}, preceded by the qualified name of the parent command, if any, separated by a space.
 4356             * @return {@link #DEFAULT_COMMAND_NAME} by default, initialized from {@link Command#name()} and the parent command if defined.
 4357             * @since 3.0.1 */
 4358            public String qualifiedName() { return qualifiedName(" "); }
 4359            /** 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.
 4360             * @return {@link #DEFAULT_COMMAND_NAME} by default, initialized from {@link Command#name()} and the parent command if any.
 4361             * @param separator the string to put between the names of the commands in the hierarchy
 4362             * @since 3.6 */
 4363            public String qualifiedName(String separator) {
 4364                String result = name();
 4365                if (parent() != null) { result = parent().qualifiedName(separator) + separator + result; }
 4366                return result;
 4367            }
 4368
 4369            /** Returns version information for this command, to print to the console when the user specifies an
 4370             * {@linkplain OptionSpec#versionHelp() option} to request version help. This is not part of the usage help message.
 4371             * @return the version strings generated by the {@link #versionProvider() version provider} if one is set, otherwise the {@linkplain #version(String...) version literals}*/
 4372            public String[] version() {
 4373                if (versionProvider != null) {
 4374                    try {
 4375                        return versionProvider.getVersion();
 4376                    } catch (Exception ex) {
 4377                        String msg = "Could not get version info from " + versionProvider + ": " + ex;
 4378                        throw new ExecutionException(this.commandLine, msg, ex);
 4379                    }
 4380                }
 4381                return version == null ? UsageMessageSpec.DEFAULT_MULTI_LINE : version;
 4382            }
 4383    
 4384            /** Returns the version provider for this command, to generate the {@link #version()} strings.
 4385             * @return the version provider or {@code null} if the version strings should be returned from the {@linkplain #version(String...) version literals}.*/
 4386            public IVersionProvider versionProvider() { return versionProvider; }
 4387
 4388            /** Returns whether this subcommand is a help command, and required options and positional
 4389             * parameters of the parent command should not be validated.
 4390             * @return {@code true} if this subcommand is a help command and picocli should not check for missing required
 4391             *      options and positional parameters on the parent command
 4392             * @see Command#helpCommand() */
 4393            public boolean helpCommand() { return (isHelpCommand == null) ? DEFAULT_IS_HELP_COMMAND : isHelpCommand; }
 4394
 4395            /** Returns {@code true} if the standard help options have been mixed in with this command, {@code false} otherwise. */
 4396            public boolean mixinStandardHelpOptions() { return mixins.containsKey(AutoHelpMixin.KEY); }
 4397
 4398            /** Returns a string representation of this command, used in error messages and trace messages. */
 4399            public String toString() { return toString; }
 4400
 4401            /** Sets the String to use as the program name in the synopsis line of the help message.
 4402             * @return this CommandSpec for method chaining */
 4403            public CommandSpec name(String name) { this.name = name; return this; }
 4404
 4405            /** Sets the alternative names by which this subcommand is recognized on the command line.
 4406             * @return this CommandSpec for method chaining
 4407             * @since 3.1 */
 4408            public CommandSpec aliases(String... aliases) {
 4409                this.aliases = new LinkedHashSet<String>(Arrays.asList(aliases == null ? new String[0] : aliases));
 4410                return this;
 4411            }
 4412
 4413            /** Returns the default value provider for this command.
 4414             * @return the default value provider or {@code null}
 4415             * @since 3.6 */
 4416            public IDefaultValueProvider defaultValueProvider() { return defaultValueProvider; }
 4417
 4418            /** Sets default value provider for this command.
 4419             * @param defaultValueProvider the default value provider to use, or {@code null}.
 4420             * @return this CommandSpec for method chaining
 4421             * @since 3.6 */
 4422            public CommandSpec defaultValueProvider(IDefaultValueProvider  defaultValueProvider) { this.defaultValueProvider = defaultValueProvider; return this; }
 4423
 4424            /** Sets version information literals for this command, to print to the console when the user specifies an
 4425             * {@linkplain OptionSpec#versionHelp() option} to request version help. Only used if no {@link #versionProvider() versionProvider} is set.
 4426             * @return this CommandSpec for method chaining */
 4427            public CommandSpec version(String... version) { this.version = version; return this; }
 4428    
 4429            /** Sets version provider for this command, to generate the {@link #version()} strings.
 4430             * @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.
 4431             * @return this CommandSpec for method chaining */
 4432            public CommandSpec versionProvider(IVersionProvider versionProvider) { this.versionProvider = versionProvider; return this; }
 4433
 4434            /** Sets whether this is a help command and required parameter checking should be suspended.
 4435             * @return this CommandSpec for method chaining
 4436             * @see Command#helpCommand() */
 4437            public CommandSpec helpCommand(boolean newValue) {isHelpCommand = newValue; return this;}
 4438
 4439            /** Sets whether the standard help options should be mixed in with this command.
 4440             * @return this CommandSpec for method chaining
 4441             * @see Command#mixinStandardHelpOptions() */
 4442            public CommandSpec mixinStandardHelpOptions(boolean newValue) {
 4443                if (newValue) {
 4444                    CommandSpec mixin = CommandSpec.forAnnotatedObject(new AutoHelpMixin(), new DefaultFactory());
 4445                    addMixin(AutoHelpMixin.KEY, mixin);
 4446                } else {
 4447                    CommandSpec helpMixin = mixins.remove(AutoHelpMixin.KEY);
 4448                    if (helpMixin != null) {
 4449                        options.removeAll(helpMixin.options);
 4450                        for (OptionSpec option : helpMixin.options()) {
 4451                            for (String name : option.names) {
 4452                                optionsByNameMap.remove(name);
 4453                                if (name.length() == 2 && name.startsWith("-")) { posixOptionsByKeyMap.remove(name.charAt(1)); }
 4454                            }
 4455                        }
 4456                    }
 4457                }
 4458                return this;
 4459            }
 4460
 4461            /** Sets the string representation of this command, used in error messages and trace messages.
 4462             * @param newValue the string representation
 4463             * @return this CommandSpec for method chaining */
 4464            public CommandSpec withToString(String newValue) { this.toString = newValue; return this; }
 4465
 4466            /**
 4467             * Updates the following attributes from the specified {@code @Command} annotation:
 4468             * aliases, {@link ParserSpec#separator() parser separator}, command name, version, help command,
 4469             * version provider, default provider and {@link UsageMessageSpec usage message spec}.
 4470             * @param cmd the {@code @Command} annotation to get attribute values from
 4471             * @param factory factory used to instantiate classes
 4472             * @since 3.7
 4473             */
 4474            public void updateCommandAttributes(Command cmd, IFactory factory) {
 4475                aliases(cmd.aliases());
 4476                parser().updateSeparator(cmd.separator());
 4477                updateName(cmd.name());
 4478                updateVersion(cmd.version());
 4479                updateHelpCommand(cmd.helpCommand());
 4480                updateAddMethodSubcommands(cmd.addMethodSubcommands());
 4481                usageMessage().updateFromCommand(cmd, this);
 4482
 4483                if (factory != null) {
 4484                    updateVersionProvider(cmd.versionProvider(), factory);
 4485                    initDefaultValueProvider(cmd.defaultValueProvider(), factory);
 4486                }
 4487            }
 4488
 4489            void initName(String value)                 { if (initializable(name, value, DEFAULT_COMMAND_NAME))                           {name = value;} }
 4490            void initHelpCommand(boolean value)         { if (initializable(isHelpCommand, value, DEFAULT_IS_HELP_COMMAND))               {isHelpCommand = value;} }
 4491            void initVersion(String[] value)            { if (initializable(version, value, UsageMessageSpec.DEFAULT_MULTI_LINE))         {version = value.clone();} }
 4492            void initVersionProvider(IVersionProvider value) { if (versionProvider == null) { versionProvider = value; } }
 4493            void initDefaultValueProvider(IDefaultValueProvider value) { if (defaultValueProvider == null) { defaultValueProvider = value; } }
 4494            void initDefaultValueProvider(Class<? extends IDefaultValueProvider> value, IFactory factory) {
 4495                if (initializable(defaultValueProvider, value, NoDefaultProvider.class)) { defaultValueProvider = (DefaultFactory.createDefaultValueProvider(factory, value)); }
 4496            }
 4497            void updateName(String value)               { if (isNonDefault(value, DEFAULT_COMMAND_NAME))                 {name = value;} }
 4498            void updateHelpCommand(boolean value)       { if (isNonDefault(value, DEFAULT_IS_HELP_COMMAND))              {isHelpCommand = value;} }
 4499            void updateAddMethodSubcommands(boolean value) { if (isNonDefault(value, DEFAULT_IS_ADD_METHOD_SUBCOMMANDS)) {isAddMethodSubcommands = value;} }
 4500            void updateVersion(String[] value)          { if (isNonDefault(value, UsageMessageSpec.DEFAULT_MULTI_LINE))  {version = value.clone();} }
 4501            void updateVersionProvider(Class<? extends IVersionProvider> value, IFactory factory) {
 4502                if (isNonDefault(value, NoVersionProvider.class)) { versionProvider = (DefaultFactory.createVersionProvider(factory, value)); }
 4503            }
 4504
 4505            /** Returns the option with the specified short name, or {@code null} if no option with that name is defined for this command. */
 4506            public OptionSpec findOption(char shortName) { return findOption(shortName, options()); }
 4507            /** Returns the option with the specified name, or {@code null} if no option with that name is defined for this command.
 4508             * @param name used to search the options. May include option name prefix characters or not. */
 4509            public OptionSpec findOption(String name) { return findOption(name, options()); }
 4510
 4511            static OptionSpec findOption(char shortName, Iterable<OptionSpec> options) {
 4512                for (OptionSpec option : options) {
 4513                    for (String name : option.names()) {
 4514                        if (name.length() == 2 && name.charAt(0) == '-' && name.charAt(1) == shortName) { return option; }
 4515                        if (name.length() == 1 && name.charAt(0) == shortName) { return option; }
 4516                    }
 4517                }
 4518                return null;
 4519            }
 4520            static OptionSpec findOption(String name, List<OptionSpec> options) {
 4521                for (OptionSpec option : options) {
 4522                    for (String prefixed : option.names()) {
 4523                        if (prefixed.equals(name) || stripPrefix(prefixed).equals(name)) { return option; }
 4524                    }
 4525                }
 4526                return null;
 4527            }
 4528            static String stripPrefix(String prefixed) {
 4529                for (int i = 0; i < prefixed.length(); i++) {
 4530                    if (Character.isJavaIdentifierPart(prefixed.charAt(i))) { return prefixed.substring(i); }
 4531                }
 4532                return prefixed;
 4533            }
 4534            List<String> findOptionNamesWithPrefix(String prefix) {
 4535                List<String> result = new ArrayList<String>();
 4536                for (OptionSpec option : options()) {
 4537                    for (String name : option.names()) {
 4538                        if (stripPrefix(name).startsWith(prefix)) { result.add(name); }
 4539                    }
 4540                }
 4541                return result;
 4542            }
 4543
 4544            boolean resemblesOption(String arg, Tracer tracer) {
 4545                if (parser().unmatchedOptionsArePositionalParams()) {
 4546                    if (tracer != null && tracer.isDebug()) {tracer.debug("Parser is configured to treat all unmatched options as positional parameter%n", arg);}
 4547                    return false;
 4548                }
 4549                if (arg.length() == 1) {
 4550                    if (tracer != null && tracer.isDebug()) {tracer.debug("Single-character arguments that don't match known options are considered positional parameters%n", arg);}
 4551                    return false;
 4552                }
 4553                if (options().isEmpty()) {
 4554                    boolean result = arg.startsWith("-");
 4555                    if (tracer != null && tracer.isDebug()) {tracer.debug("'%s' %s an option%n", arg, (result ? "resembles" : "doesn't resemble"));}
 4556                    return result;
 4557                }
 4558                int count = 0;
 4559                for (String optionName : optionsMap().keySet()) {
 4560                    for (int i = 0; i < arg.length(); i++) {
 4561                        if (optionName.length() > i && arg.charAt(i) == optionName.charAt(i)) { count++; } else { break; }
 4562                    }
 4563                }
 4564                boolean result = count > 0 && count * 10 >= optionsMap().size() * 9; // at least one prefix char in common with 9 out of 10 options
 4565                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());}
 4566                return result;
 4567            }
 4568        }
 4569        private static boolean initializable(Object current, Object candidate, Object defaultValue) {
 4570            return current == null && isNonDefault(candidate, defaultValue);
 4571        }
 4572        private static boolean initializable(Object current, Object[] candidate, Object[] defaultValue) {
 4573            return current == null && isNonDefault(candidate, defaultValue);
 4574        }
 4575        private static boolean isNonDefault(Object candidate, Object defaultValue) {
 4576            return !Assert.notNull(defaultValue, "defaultValue").equals(candidate);
 4577        }
 4578        private static boolean isNonDefault(Object[] candidate, Object[] defaultValue) {
 4579            return !Arrays.equals(Assert.notNull(defaultValue, "defaultValue"), candidate);
 4580        }
 4581        /** Models the usage help message specification and can be used to customize the usage help message.
 4582         * <p>
 4583         * This class provides two ways to customize the usage help message:
 4584         * </p>
 4585         * <ul>
 4586         *     <li>Change the text of the predefined sections (this may also be done declaratively using the annotations)</li>
 4587         *     <li>Add custom sections, or remove or re-order predefined sections</li>
 4588         * </ul>
 4589         * <p>
 4590         * The pre-defined sections have getters and setters that return a String (or array of Strings). For example:
 4591         * {@link #description()} and {@link #description(String...)} or {@link #header()} and {@link #header(String...)}.
 4592         * </p><p>
 4593         * Changing the section order, or adding custom sections can be accomplished with {@link #sectionKeys(List)} and {@link #sectionMap(Map)}.
 4594         * This gives complete freedom on how a usage help message section is rendered, but it also means that the {@linkplain IHelpSectionRenderer section renderer}
 4595         * is responsible for all aspects of rendering the section, including layout and emitting ANSI escape codes.
 4596         * 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.
 4597         * </p><p>
 4598         * The usage help message is created more or less like this:
 4599         * </p>
 4600         * <pre>
 4601         * // CommandLine.usage(...) or CommandLine.getUsageMessage(...)
 4602         * Help.ColorScheme colorScheme = Help.defaultColorScheme(Help.Ansi.AUTO);
 4603         * Help help = getHelpFactory().create(getCommandSpec(), colorScheme)
 4604         * StringBuilder result = new StringBuilder();
 4605         * for (String key : getHelpSectionKeys()) {
 4606         *     IHelpSectionRenderer renderer = getHelpSectionMap().get(key);
 4607         *     if (renderer != null) { result.append(renderer.render(help)); }
 4608         * }
 4609         * // return or print result
 4610         * </pre>
 4611         * <p>
 4612         * Where the default {@linkplain #sectionMap() help section map} is constructed like this:</p>
 4613         * <pre>{@code
 4614         * // The default section renderers delegate to methods in Help for their implementation
 4615         * // (using Java 8 lambda notation for brevity):
 4616         * Map<String, IHelpSectionRenderer> sectionMap = new HashMap<>();
 4617         * sectionMap.put(SECTION_KEY_HEADER_HEADING,         help -> help.headerHeading());
 4618         * sectionMap.put(SECTION_KEY_HEADER,                 help -> help.header());
 4619         * sectionMap.put(SECTION_KEY_SYNOPSIS_HEADING,       help -> help.synopsisHeading());      //e.g. Usage:
 4620         * sectionMap.put(SECTION_KEY_SYNOPSIS,               help -> help.synopsis(help.synopsisHeadingLength())); //e.g. <cmd> [OPTIONS] <subcmd> [COMMAND-OPTIONS] [ARGUMENTS]
 4621         * sectionMap.put(SECTION_KEY_DESCRIPTION_HEADING,    help -> help.descriptionHeading());   //e.g. %nDescription:%n%n
 4622         * sectionMap.put(SECTION_KEY_DESCRIPTION,            help -> help.description());          //e.g. {"Converts foos to bars.", "Use options to control conversion mode."}
 4623         * sectionMap.put(SECTION_KEY_PARAMETER_LIST_HEADING, help -> help.parameterListHeading()); //e.g. %nPositional parameters:%n%n
 4624         * sectionMap.put(SECTION_KEY_PARAMETER_LIST,         help -> help.parameterList());        //e.g. [FILE...] the files to convert
 4625         * sectionMap.put(SECTION_KEY_OPTION_LIST_HEADING,    help -> help.optionListHeading());    //e.g. %nOptions:%n%n
 4626         * sectionMap.put(SECTION_KEY_OPTION_LIST,            help -> help.optionList());           //e.g. -h, --help   displays this help and exits
 4627         * sectionMap.put(SECTION_KEY_COMMAND_LIST_HEADING,   help -> help.commandListHeading());   //e.g. %nCommands:%n%n
 4628         * sectionMap.put(SECTION_KEY_COMMAND_LIST,           help -> help.commandList());          //e.g.    add       adds the frup to the frooble
 4629         * sectionMap.put(SECTION_KEY_FOOTER_HEADING,         help -> help.footerHeading());
 4630         * sectionMap.put(SECTION_KEY_FOOTER,                 help -> help.footer());
 4631         * }</pre>
 4632         *
 4633         * @since 3.0 */
 4634        public static class UsageMessageSpec {
 4635
 4636            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Header Heading section.
 4637             * The default renderer for this section calls {@link Help#headerHeading(Object...)}.
 4638             * @since 3.9 */
 4639            public static final String SECTION_KEY_HEADER_HEADING = "headerHeading";
 4640
 4641            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Header section.
 4642             * The default renderer for this section calls {@link Help#header(Object...)}.
 4643             * @since 3.9 */
 4644            public static final String SECTION_KEY_HEADER = "header";
 4645
 4646            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Synopsis Heading section.
 4647             * The default renderer for this section calls {@link Help#synopsisHeading(Object...)}.
 4648             * @since 3.9 */
 4649            public static final String SECTION_KEY_SYNOPSIS_HEADING = "synopsisHeading";
 4650
 4651            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Synopsis section.
 4652             * The default renderer for this section calls {@link Help#synopsis(int)}.
 4653             * @since 3.9 */
 4654            public static final String SECTION_KEY_SYNOPSIS = "synopsis";
 4655
 4656            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Description Heading section.
 4657             * The default renderer for this section calls {@link Help#descriptionHeading(Object...)}.
 4658             * @since 3.9 */
 4659            public static final String SECTION_KEY_DESCRIPTION_HEADING = "descriptionHeading";
 4660
 4661            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Description section.
 4662             * The default renderer for this section calls {@link Help#description(Object...)}.
 4663             * @since 3.9 */
 4664            public static final String SECTION_KEY_DESCRIPTION = "description";
 4665
 4666            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Parameter List Heading section.
 4667             * The default renderer for this section calls {@link Help#parameterListHeading(Object...)}.
 4668             * @since 3.9 */
 4669            public static final String SECTION_KEY_PARAMETER_LIST_HEADING = "parameterListHeading";
 4670
 4671            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Parameter List section.
 4672             * The default renderer for this section calls {@link Help#parameterList()}.
 4673             * @since 3.9 */
 4674            public static final String SECTION_KEY_PARAMETER_LIST = "parameterList";
 4675
 4676            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Option List Heading section.
 4677             * The default renderer for this section calls {@link Help#optionListHeading(Object...)}.
 4678             * @since 3.9 */
 4679            public static final String SECTION_KEY_OPTION_LIST_HEADING = "optionListHeading";
 4680
 4681            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Option List section.
 4682             * The default renderer for this section calls {@link Help#optionList()}.
 4683             * @since 3.9 */
 4684            public static final String SECTION_KEY_OPTION_LIST = "optionList";
 4685
 4686            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Subcommand List Heading section.
 4687             * The default renderer for this section calls {@link Help#commandListHeading(Object...)}.
 4688             * @since 3.9 */
 4689            public static final String SECTION_KEY_COMMAND_LIST_HEADING = "commandListHeading";
 4690
 4691            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Subcommand List section.
 4692             * The default renderer for this section calls {@link Help#commandList()}.
 4693             * @since 3.9 */
 4694            public static final String SECTION_KEY_COMMAND_LIST = "commandList";
 4695
 4696            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Footer Heading section.
 4697             * The default renderer for this section calls {@link Help#footerHeading(Object...)}.
 4698             * @since 3.9 */
 4699            public static final String SECTION_KEY_FOOTER_HEADING = "footerHeading";
 4700
 4701            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Footer section.
 4702             * The default renderer for this section calls {@link Help#footer(Object...)}.
 4703             * @since 3.9 */
 4704            public static final String SECTION_KEY_FOOTER = "footer";
 4705
 4706            /** Constant holding the default usage message width: <code>{@value}</code>. */
 4707            public  final static int DEFAULT_USAGE_WIDTH = 80;
 4708            private final static int MINIMUM_USAGE_WIDTH = 55;
 4709
 4710            /** Constant String holding the default synopsis heading: <code>{@value}</code>. */
 4711            static final String DEFAULT_SYNOPSIS_HEADING = "Usage: ";
 4712
 4713            /** Constant String holding the default command list heading: <code>{@value}</code>. */
 4714            static final String DEFAULT_COMMAND_LIST_HEADING = "Commands:%n";
 4715
 4716            /** Constant String holding the default string that separates options from option parameters: {@code ' '} ({@value}). */
 4717            static final char DEFAULT_REQUIRED_OPTION_MARKER = ' ';
 4718
 4719            /** Constant Boolean holding the default setting for whether to abbreviate the synopsis: <code>{@value}</code>.*/
 4720            static final Boolean DEFAULT_ABBREVIATE_SYNOPSIS = Boolean.FALSE;
 4721
 4722            /** Constant Boolean holding the default setting for whether to sort the options alphabetically: <code>{@value}</code>.*/
 4723            static final Boolean DEFAULT_SORT_OPTIONS = Boolean.TRUE;
 4724
 4725            /** Constant Boolean holding the default setting for whether to show default values in the usage help message: <code>{@value}</code>.*/
 4726            static final Boolean DEFAULT_SHOW_DEFAULT_VALUES = Boolean.FALSE;
 4727
 4728            /** Constant Boolean holding the default setting for whether this command should be listed in the usage help of the parent command: <code>{@value}</code>.*/
 4729            static final Boolean DEFAULT_HIDDEN = Boolean.FALSE;
 4730
 4731            static final String DEFAULT_SINGLE_VALUE = "";
 4732            static final String[] DEFAULT_MULTI_LINE = {};
 4733
 4734            private IHelpFactory helpFactory;
 4735
 4736            private List<String> sectionKeys = Collections.unmodifiableList(Arrays.asList(
 4737                    SECTION_KEY_HEADER_HEADING,
 4738                    SECTION_KEY_HEADER,
 4739                    SECTION_KEY_SYNOPSIS_HEADING,
 4740                    SECTION_KEY_SYNOPSIS,
 4741                    SECTION_KEY_DESCRIPTION_HEADING,
 4742                    SECTION_KEY_DESCRIPTION,
 4743                    SECTION_KEY_PARAMETER_LIST_HEADING,
 4744                    SECTION_KEY_PARAMETER_LIST,
 4745                    SECTION_KEY_OPTION_LIST_HEADING,
 4746                    SECTION_KEY_OPTION_LIST,
 4747                    SECTION_KEY_COMMAND_LIST_HEADING,
 4748                    SECTION_KEY_COMMAND_LIST,
 4749                    SECTION_KEY_FOOTER_HEADING,
 4750                    SECTION_KEY_FOOTER));
 4751
 4752            private Map<String, IHelpSectionRenderer> helpSectionRendererMap = createHelpSectionRendererMap();
 4753
 4754            private String[] description;
 4755            private String[] customSynopsis;
 4756            private String[] header;
 4757            private String[] footer;
 4758            private Boolean abbreviateSynopsis;
 4759            private Boolean sortOptions;
 4760            private Boolean showDefaultValues;
 4761            private Boolean hidden;
 4762            private Character requiredOptionMarker;
 4763            private String headerHeading;
 4764            private String synopsisHeading;
 4765            private String descriptionHeading;
 4766            private String parameterListHeading;
 4767            private String optionListHeading;
 4768            private String commandListHeading;
 4769            private String footerHeading;
 4770            private int width = DEFAULT_USAGE_WIDTH;
 4771
 4772            private Messages messages;
 4773
 4774            /**
 4775             * Sets the maximum usage help message width to the specified value. Longer values are wrapped.
 4776             * @param newValue the new maximum usage help message width. Must be 55 or greater.
 4777             * @return this {@code UsageMessageSpec} for method chaining
 4778             * @throws IllegalArgumentException if the specified width is less than 55
 4779             */
 4780            public UsageMessageSpec width(int newValue) {
 4781                if (newValue < MINIMUM_USAGE_WIDTH) {
 4782                    throw new InitializationException("Invalid usage message width " + newValue + ". Minimum value is " + MINIMUM_USAGE_WIDTH);
 4783                }
 4784                width = newValue; return this;
 4785            }
 4786
 4787            private static int getSysPropertyWidthOrDefault(int defaultWidth) {
 4788                String userValue = System.getProperty("picocli.usage.width");
 4789                if (userValue == null) { return defaultWidth; }
 4790                try {
 4791                    int width = Integer.parseInt(userValue);
 4792                    if (width < MINIMUM_USAGE_WIDTH) {
 4793                        new Tracer().warn("Invalid picocli.usage.width value %d. Using minimum usage width %d.%n", width, MINIMUM_USAGE_WIDTH);
 4794                        return MINIMUM_USAGE_WIDTH;
 4795                    }
 4796                    return width;
 4797                } catch (NumberFormatException ex) {
 4798                    new Tracer().warn("Invalid picocli.usage.width value '%s'. Using usage width %d.%n", userValue, defaultWidth);
 4799                    return defaultWidth;
 4800                }
 4801            }
 4802
 4803            /** Returns the maximum usage help message width. Derived from system property {@code "picocli.usage.width"}
 4804             * if set, otherwise returns the value set via the {@link #width(int)} method, or if not set, the {@linkplain #DEFAULT_USAGE_WIDTH default width}.
 4805             * @return the maximum usage help message width. Never returns less than 55. */
 4806            public int width() { return getSysPropertyWidthOrDefault(width); }
 4807
 4808            /** Returns the help section renderers for the predefined section keys. see: {@link #sectionKeys()} */
 4809            private Map<String, IHelpSectionRenderer> createHelpSectionRendererMap() {
 4810                Map<String, IHelpSectionRenderer> result = new HashMap<String, IHelpSectionRenderer>();
 4811
 4812                result.put(SECTION_KEY_HEADER_HEADING,         new IHelpSectionRenderer() { public String render(Help help) { return help.headerHeading(); } });
 4813                result.put(SECTION_KEY_HEADER,                 new IHelpSectionRenderer() { public String render(Help help) { return help.header(); } });
 4814                //e.g. Usage:
 4815                result.put(SECTION_KEY_SYNOPSIS_HEADING,       new IHelpSectionRenderer() { public String render(Help help) { return help.synopsisHeading(); } });
 4816                //e.g. &lt;main class&gt; [OPTIONS] &lt;command&gt; [COMMAND-OPTIONS] [ARGUMENTS]
 4817                result.put(SECTION_KEY_SYNOPSIS,               new IHelpSectionRenderer() { public String render(Help help) { return help.synopsis(help.synopsisHeadingLength()); } });
 4818                //e.g. %nDescription:%n%n
 4819                result.put(SECTION_KEY_DESCRIPTION_HEADING,    new IHelpSectionRenderer() { public String render(Help help) { return help.descriptionHeading(); } });
 4820                //e.g. {"Converts foos to bars.", "Use options to control conversion mode."}
 4821                result.put(SECTION_KEY_DESCRIPTION,            new IHelpSectionRenderer() { public String render(Help help) { return help.description(); } });
 4822                //e.g. %nPositional parameters:%n%n
 4823                result.put(SECTION_KEY_PARAMETER_LIST_HEADING, new IHelpSectionRenderer() { public String render(Help help) { return help.parameterListHeading(); } });
 4824                //e.g. [FILE...] the files to convert
 4825                result.put(SECTION_KEY_PARAMETER_LIST,         new IHelpSectionRenderer() { public String render(Help help) { return help.parameterList(); } });
 4826                //e.g. %nOptions:%n%n
 4827                result.put(SECTION_KEY_OPTION_LIST_HEADING,    new IHelpSectionRenderer() { public String render(Help help) { return help.optionListHeading(); } });
 4828                //e.g. -h, --help   displays this help and exits
 4829                result.put(SECTION_KEY_OPTION_LIST,            new IHelpSectionRenderer() { public String render(Help help) { return help.optionList(); } });
 4830                //e.g. %nCommands:%n%n
 4831                result.put(SECTION_KEY_COMMAND_LIST_HEADING,   new IHelpSectionRenderer() { public String render(Help help) { return help.commandListHeading(); } });
 4832                //e.g.    add       adds the frup to the frooble
 4833                result.put(SECTION_KEY_COMMAND_LIST,           new IHelpSectionRenderer() { public String render(Help help) { return help.commandList(); } });
 4834                result.put(SECTION_KEY_FOOTER_HEADING,         new IHelpSectionRenderer() { public String render(Help help) { return help.footerHeading(); } });
 4835                result.put(SECTION_KEY_FOOTER,                 new IHelpSectionRenderer() { public String render(Help help) { return help.footer(); } });
 4836                return result;
 4837            }
 4838
 4839            /**
 4840             * Returns the section keys in the order that the usage help message should render the sections.
 4841             * This ordering may be modified with the {@link #sectionKeys(List) sectionKeys setter}. The default keys are (in order):
 4842             * <ol>
 4843             *   <li>{@link UsageMessageSpec#SECTION_KEY_HEADER_HEADING SECTION_KEY_HEADER_HEADING}</li>
 4844             *   <li>{@link UsageMessageSpec#SECTION_KEY_HEADER SECTION_KEY_HEADER}</li>
 4845             *   <li>{@link UsageMessageSpec#SECTION_KEY_SYNOPSIS_HEADING SECTION_KEY_SYNOPSIS_HEADING}</li>
 4846             *   <li>{@link UsageMessageSpec#SECTION_KEY_SYNOPSIS SECTION_KEY_SYNOPSIS}</li>
 4847             *   <li>{@link UsageMessageSpec#SECTION_KEY_DESCRIPTION_HEADING SECTION_KEY_DESCRIPTION_HEADING}</li>
 4848             *   <li>{@link UsageMessageSpec#SECTION_KEY_DESCRIPTION SECTION_KEY_DESCRIPTION}</li>
 4849             *   <li>{@link UsageMessageSpec#SECTION_KEY_PARAMETER_LIST_HEADING SECTION_KEY_PARAMETER_LIST_HEADING}</li>
 4850             *   <li>{@link UsageMessageSpec#SECTION_KEY_PARAMETER_LIST SECTION_KEY_PARAMETER_LIST}</li>
 4851             *   <li>{@link UsageMessageSpec#SECTION_KEY_OPTION_LIST_HEADING SECTION_KEY_OPTION_LIST_HEADING}</li>
 4852             *   <li>{@link UsageMessageSpec#SECTION_KEY_OPTION_LIST SECTION_KEY_OPTION_LIST}</li>
 4853             *   <li>{@link UsageMessageSpec#SECTION_KEY_COMMAND_LIST_HEADING SECTION_KEY_COMMAND_LIST_HEADING}</li>
 4854             *   <li>{@link UsageMessageSpec#SECTION_KEY_COMMAND_LIST SECTION_KEY_COMMAND_LIST}</li>
 4855             *   <li>{@link UsageMessageSpec#SECTION_KEY_FOOTER_HEADING SECTION_KEY_FOOTER_HEADING}</li>
 4856             *   <li>{@link UsageMessageSpec#SECTION_KEY_FOOTER SECTION_KEY_FOOTER}</li>
 4857             * </ol>
 4858             * @since 3.9
 4859             */
 4860            public List<String> sectionKeys() { return sectionKeys; }
 4861
 4862            /**
 4863             * Sets the section keys in the order that the usage help message should render the sections.
 4864             * @see #sectionKeys
 4865             * @since 3.9
 4866             */
 4867            public UsageMessageSpec sectionKeys(List<String> keys) { sectionKeys = Collections.unmodifiableList(new ArrayList<String>(keys)); return this; }
 4868
 4869            /**
 4870             * Returns the map of section keys and renderers used to construct the usage help message.
 4871             * The usage help message can be customized by adding, replacing and removing section renderers from this map.
 4872             * Sections can be reordered with the {@link #sectionKeys(List) sectionKeys setter}.
 4873             * Sections that are either not in this map or not in the list returned by {@link #sectionKeys() sectionKeys} are omitted.
 4874             * @see #sectionKeys
 4875             * @since 3.9
 4876             */
 4877            public Map<String, IHelpSectionRenderer> sectionMap() { return helpSectionRendererMap; }
 4878
 4879            /**
 4880             * Sets the map of section keys and renderers used to construct the usage help message to a copy of the specified map.
 4881             * @param map the mapping of section keys to their renderers, must be non-{@code null}.
 4882             * @return this UsageMessageSpec for method chaining
 4883             * @see #sectionKeys
 4884             * @see #setHelpSectionMap(Map)
 4885             * @since 3.9
 4886             */
 4887            public UsageMessageSpec sectionMap(Map<String, IHelpSectionRenderer> map) { this.helpSectionRendererMap = new HashMap<String, IHelpSectionRenderer>(map); return this; }
 4888
 4889            /** Returns the {@code IHelpFactory} that is used to construct the usage help message.
 4890             * @see #setHelpFactory(IHelpFactory)
 4891             * @since 3.9
 4892             */
 4893            public IHelpFactory helpFactory() {
 4894                if (helpFactory == null) {
 4895                    helpFactory = new DefaultHelpFactory();
 4896                }
 4897                return helpFactory;
 4898            }
 4899
 4900            /** Sets a new {@code IHelpFactory} to customize the usage help message.
 4901             * @param helpFactory the new help factory. Must be non-{@code null}.
 4902             * @return this {@code UsageMessageSpec} object, to allow method chaining
 4903             */
 4904            public UsageMessageSpec helpFactory(IHelpFactory helpFactory) {
 4905                this.helpFactory = Assert.notNull(helpFactory, "helpFactory");
 4906                return this;
 4907            }
 4908
 4909            private String str(String localized, String value, String defaultValue) {
 4910                return localized != null ? localized : (value != null ? value : defaultValue);
 4911            }
 4912            private String[] arr(String[] localized, String[] value, String[] defaultValue) {
 4913                return localized != null ? localized : (value != null ? value.clone() : defaultValue);
 4914            }
 4915            private String   resourceStr(String key) { return messages == null ? null : messages.getString(key, null); }
 4916            private String[] resourceArr(String key) { return messages == null ? null : messages.getStringArray(key, null); }
 4917
 4918            /** Returns the optional heading preceding the header section. Initialized from {@link Command#headerHeading()}, or null. */
 4919            public String headerHeading() { return str(resourceStr("usage.headerHeading"), headerHeading, DEFAULT_SINGLE_VALUE); }
 4920
 4921            /** Returns the optional header lines displayed at the top of the help message. For subcommands, the first header line is
 4922             * displayed in the list of commands. Values are initialized from {@link Command#header()}
 4923             * if the {@code Command} annotation is present, otherwise this is an empty array and the help message has no
 4924             * header. Applications may programmatically set this field to create a custom help message. */
 4925            public String[] header() { return arr(resourceArr("usage.header"), header, DEFAULT_MULTI_LINE); }
 4926
 4927            /** Returns the optional heading preceding the synopsis. Initialized from {@link Command#synopsisHeading()}, {@code "Usage: "} by default. */
 4928            public String synopsisHeading() { return str(resourceStr("usage.synopsisHeading"), synopsisHeading, DEFAULT_SYNOPSIS_HEADING); }
 4929
 4930            /** Returns whether the synopsis line(s) should show an abbreviated synopsis without detailed option names. */
 4931            public boolean abbreviateSynopsis() { return (abbreviateSynopsis == null) ? DEFAULT_ABBREVIATE_SYNOPSIS : abbreviateSynopsis; }
 4932
 4933            /** Returns the optional custom synopsis lines to use instead of the auto-generated synopsis.
 4934             * Initialized from {@link Command#customSynopsis()} if the {@code Command} annotation is present,
 4935             * otherwise this is an empty array and the synopsis is generated.
 4936             * Applications may programmatically set this field to create a custom help message. */
 4937            public String[] customSynopsis() { return arr(resourceArr("usage.customSynopsis"), customSynopsis, DEFAULT_MULTI_LINE); }
 4938
 4939            /** Returns the optional heading preceding the description section. Initialized from {@link Command#descriptionHeading()}, or null. */
 4940            public String descriptionHeading() { return str(resourceStr("usage.descriptionHeading"), descriptionHeading, DEFAULT_SINGLE_VALUE); }
 4941
 4942            /** Returns the optional text lines to use as the description of the help message, displayed between the synopsis and the
 4943             * options list. Initialized from {@link Command#description()} if the {@code Command} annotation is present,
 4944             * otherwise this is an empty array and the help message has no description.
 4945             * Applications may programmatically set this field to create a custom help message. */
 4946            public String[] description() { return arr(resourceArr("usage.description"), description, DEFAULT_MULTI_LINE); }
 4947
 4948            /** Returns the optional heading preceding the parameter list. Initialized from {@link Command#parameterListHeading()}, or null. */
 4949            public String parameterListHeading() { return str(resourceStr("usage.parameterListHeading"), parameterListHeading, DEFAULT_SINGLE_VALUE); }
 4950
 4951            /** Returns the optional heading preceding the options list. Initialized from {@link Command#optionListHeading()}, or null. */
 4952            public String optionListHeading() { return str(resourceStr("usage.optionListHeading"), optionListHeading, DEFAULT_SINGLE_VALUE); }
 4953
 4954            /** Returns whether the options list in the usage help message should be sorted alphabetically. */
 4955            public boolean sortOptions() { return (sortOptions == null) ? DEFAULT_SORT_OPTIONS : sortOptions; }
 4956
 4957            /** Returns the character used to prefix required options in the options list. */
 4958            public char requiredOptionMarker() { return (requiredOptionMarker == null) ? DEFAULT_REQUIRED_OPTION_MARKER : requiredOptionMarker; }
 4959
 4960            /** Returns whether the options list in the usage help message should show default values for all non-boolean options. */
 4961            public boolean showDefaultValues() { return (showDefaultValues == null) ? DEFAULT_SHOW_DEFAULT_VALUES : showDefaultValues; }
 4962
 4963            /**
 4964             * Returns whether this command should be hidden from the usage help message of the parent command.
 4965             * @return {@code true} if this command should not appear in the usage help message of the parent command
 4966             */
 4967            public boolean hidden() { return (hidden == null) ? DEFAULT_HIDDEN : hidden; }
 4968
 4969            /** Returns the optional heading preceding the subcommand list. Initialized from {@link Command#commandListHeading()}. {@code "Commands:%n"} by default. */
 4970            public String commandListHeading() { return str(resourceStr("usage.commandListHeading"), commandListHeading, DEFAULT_COMMAND_LIST_HEADING); }
 4971
 4972            /** Returns the optional heading preceding the footer section. Initialized from {@link Command#footerHeading()}, or null. */
 4973            public String footerHeading() { return str(resourceStr("usage.footerHeading"), footerHeading, DEFAULT_SINGLE_VALUE); }
 4974
 4975            /** Returns the optional footer text lines displayed at the bottom of the help message. Initialized from
 4976             * {@link Command#footer()} if the {@code Command} annotation is present, otherwise this is an empty array and
 4977             * the help message has no footer.
 4978             * Applications may programmatically set this field to create a custom help message. */
 4979            public String[] footer() { return arr(resourceArr("usage.footer"), footer, DEFAULT_MULTI_LINE); }
 4980
 4981            /** Sets the heading preceding the header section. Initialized from {@link Command#headerHeading()}, or null.
 4982             * @return this UsageMessageSpec for method chaining */
 4983            public UsageMessageSpec headerHeading(String headerHeading) { this.headerHeading = headerHeading; return this; }
 4984
 4985            /** Sets the optional header lines displayed at the top of the help message. For subcommands, the first header line is
 4986             * displayed in the list of commands.
 4987             * @return this UsageMessageSpec for method chaining */
 4988            public UsageMessageSpec header(String... header) { this.header = header; return this; }
 4989
 4990            /** Sets the optional heading preceding the synopsis.
 4991             * @return this UsageMessageSpec for method chaining */
 4992            public UsageMessageSpec synopsisHeading(String newValue) {synopsisHeading = newValue; return this;}
 4993
 4994            /** Sets whether the synopsis line(s) should show an abbreviated synopsis without detailed option names.
 4995             * @return this UsageMessageSpec for method chaining */
 4996            public UsageMessageSpec abbreviateSynopsis(boolean newValue) {abbreviateSynopsis = newValue; return this;}
 4997
 4998            /** Sets the optional custom synopsis lines to use instead of the auto-generated synopsis.
 4999             * @return this UsageMessageSpec for method chaining */
 5000            public UsageMessageSpec customSynopsis(String... customSynopsis) { this.customSynopsis = customSynopsis; return this; }
 5001
 5002            /** Sets the heading preceding the description section.
 5003             * @return this UsageMessageSpec for method chaining */
 5004            public UsageMessageSpec descriptionHeading(String newValue) {descriptionHeading = newValue; return this;}
 5005
 5006            /** Sets the optional text lines to use as the description of the help message, displayed between the synopsis and the
 5007             * options list.
 5008             * @return this UsageMessageSpec for method chaining */
 5009            public UsageMessageSpec description(String... description) { this.description = description; return this; }
 5010
 5011            /** Sets the optional heading preceding the parameter list.
 5012             * @return this UsageMessageSpec for method chaining */
 5013            public UsageMessageSpec parameterListHeading(String newValue) {parameterListHeading = newValue; return this;}
 5014
 5015            /** Sets the heading preceding the options list.
 5016             * @return this UsageMessageSpec for method chaining */
 5017            public UsageMessageSpec optionListHeading(String newValue) {optionListHeading = newValue; return this;}
 5018
 5019            /** Sets whether the options list in the usage help message should be sorted alphabetically.
 5020             * @return this UsageMessageSpec for method chaining */
 5021            public UsageMessageSpec sortOptions(boolean newValue) {sortOptions = newValue; return this;}
 5022
 5023            /** Sets the character used to prefix required options in the options list.
 5024             * @return this UsageMessageSpec for method chaining */
 5025            public UsageMessageSpec requiredOptionMarker(char newValue) {requiredOptionMarker = newValue; return this;}
 5026
 5027            /** Sets whether the options list in the usage help message should show default values for all non-boolean options.
 5028             * @return this UsageMessageSpec for method chaining */
 5029            public UsageMessageSpec showDefaultValues(boolean newValue) {showDefaultValues = newValue; return this;}
 5030
 5031            /**
 5032             * Set the hidden flag on this command to control whether to show or hide it in the help usage text of the parent command.
 5033             * @param value enable or disable the hidden flag
 5034             * @return this UsageMessageSpec for method chaining
 5035             * @see Command#hidden() */
 5036            public UsageMessageSpec hidden(boolean value) { hidden = value; return this; }
 5037
 5038            /** Sets the optional heading preceding the subcommand list.
 5039             * @return this UsageMessageSpec for method chaining */
 5040            public UsageMessageSpec commandListHeading(String newValue) {commandListHeading = newValue; return this;}
 5041
 5042            /** Sets the optional heading preceding the footer section.
 5043             * @return this UsageMessageSpec for method chaining */
 5044            public UsageMessageSpec footerHeading(String newValue) {footerHeading = newValue; return this;}
 5045
 5046            /** Sets the optional footer text lines displayed at the bottom of the help message.
 5047             * @return this UsageMessageSpec for method chaining */
 5048            public UsageMessageSpec footer(String... footer) { this.footer = footer; return this; }
 5049            /** Returns the Messages for this usage help message specification, or {@code null}.
 5050             * @return the Messages object that encapsulates this {@linkplain CommandSpec#resourceBundle() command's resource bundle}
 5051             * @since 3.6 */
 5052            public Messages messages() { return messages; }
 5053            /** Sets the Messages for this usageMessage specification, and returns this UsageMessageSpec.
 5054             * @param msgs the new Messages value that encapsulates this {@linkplain CommandSpec#resourceBundle() command's resource bundle}, may be {@code null}
 5055             * @since 3.6 */
 5056            public UsageMessageSpec messages(Messages msgs) { messages = msgs; return this; }
 5057            void updateFromCommand(Command cmd, CommandSpec commandSpec) {
 5058                if (isNonDefault(cmd.synopsisHeading(), DEFAULT_SYNOPSIS_HEADING))            {synopsisHeading = cmd.synopsisHeading();}
 5059                if (isNonDefault(cmd.commandListHeading(), DEFAULT_COMMAND_LIST_HEADING))     {commandListHeading = cmd.commandListHeading();}
 5060                if (isNonDefault(cmd.requiredOptionMarker(), DEFAULT_REQUIRED_OPTION_MARKER)) {requiredOptionMarker = cmd.requiredOptionMarker();}
 5061                if (isNonDefault(cmd.abbreviateSynopsis(), DEFAULT_ABBREVIATE_SYNOPSIS))      {abbreviateSynopsis = cmd.abbreviateSynopsis();}
 5062                if (isNonDefault(cmd.sortOptions(), DEFAULT_SORT_OPTIONS))                    {sortOptions = cmd.sortOptions();}
 5063                if (isNonDefault(cmd.showDefaultValues(), DEFAULT_SHOW_DEFAULT_VALUES))       {showDefaultValues = cmd.showDefaultValues();}
 5064                if (isNonDefault(cmd.hidden(), DEFAULT_HIDDEN))                               {hidden = cmd.hidden();}
 5065                if (isNonDefault(cmd.customSynopsis(), DEFAULT_MULTI_LINE))                   {customSynopsis = cmd.customSynopsis().clone();}
 5066                if (isNonDefault(cmd.description(), DEFAULT_MULTI_LINE))                      {description = cmd.description().clone();}
 5067                if (isNonDefault(cmd.descriptionHeading(), DEFAULT_SINGLE_VALUE))             {descriptionHeading = cmd.descriptionHeading();}
 5068                if (isNonDefault(cmd.header(), DEFAULT_MULTI_LINE))                           {header = cmd.header().clone();}
 5069                if (isNonDefault(cmd.headerHeading(), DEFAULT_SINGLE_VALUE))                  {headerHeading = cmd.headerHeading();}
 5070                if (isNonDefault(cmd.footer(), DEFAULT_MULTI_LINE))                           {footer = cmd.footer().clone();}
 5071                if (isNonDefault(cmd.footerHeading(), DEFAULT_SINGLE_VALUE))                  {footerHeading = cmd.footerHeading();}
 5072                if (isNonDefault(cmd.parameterListHeading(), DEFAULT_SINGLE_VALUE))           {parameterListHeading = cmd.parameterListHeading();}
 5073                if (isNonDefault(cmd.optionListHeading(), DEFAULT_SINGLE_VALUE))              {optionListHeading = cmd.optionListHeading();}
 5074                if (isNonDefault(cmd.usageHelpWidth(), DEFAULT_USAGE_WIDTH))                  {width(cmd.usageHelpWidth());} // validate
 5075
 5076                if (!empty(cmd.resourceBundle())) { // else preserve superclass bundle
 5077                    messages(new Messages(commandSpec, cmd.resourceBundle()));
 5078                }
 5079            }
 5080            void initFromMixin(UsageMessageSpec mixin, CommandSpec commandSpec) {
 5081                if (initializable(synopsisHeading, mixin.synopsisHeading(), DEFAULT_SYNOPSIS_HEADING))                 {synopsisHeading = mixin.synopsisHeading();}
 5082                if (initializable(commandListHeading, mixin.commandListHeading(), DEFAULT_COMMAND_LIST_HEADING))       {commandListHeading = mixin.commandListHeading();}
 5083                if (initializable(requiredOptionMarker, mixin.requiredOptionMarker(), DEFAULT_REQUIRED_OPTION_MARKER)) {requiredOptionMarker = mixin.requiredOptionMarker();}
 5084                if (initializable(abbreviateSynopsis, mixin.abbreviateSynopsis(), DEFAULT_ABBREVIATE_SYNOPSIS))        {abbreviateSynopsis = mixin.abbreviateSynopsis();}
 5085                if (initializable(sortOptions, mixin.sortOptions(), DEFAULT_SORT_OPTIONS))                             {sortOptions = mixin.sortOptions();}
 5086                if (initializable(showDefaultValues, mixin.showDefaultValues(), DEFAULT_SHOW_DEFAULT_VALUES))          {showDefaultValues = mixin.showDefaultValues();}
 5087                if (initializable(hidden, mixin.hidden(), DEFAULT_HIDDEN))                                             {hidden = mixin.hidden();}
 5088                if (initializable(customSynopsis, mixin.customSynopsis(), DEFAULT_MULTI_LINE))                         {customSynopsis = mixin.customSynopsis().clone();}
 5089                if (initializable(description, mixin.description(), DEFAULT_MULTI_LINE))                               {description = mixin.description().clone();}
 5090                if (initializable(descriptionHeading, mixin.descriptionHeading(), DEFAULT_SINGLE_VALUE))               {descriptionHeading = mixin.descriptionHeading();}
 5091                if (initializable(header, mixin.header(), DEFAULT_MULTI_LINE))                                         {header = mixin.header().clone();}
 5092                if (initializable(headerHeading, mixin.headerHeading(), DEFAULT_SINGLE_VALUE))                         {headerHeading = mixin.headerHeading();}
 5093                if (initializable(footer, mixin.footer(), DEFAULT_MULTI_LINE))                                         {footer = mixin.footer().clone();}
 5094                if (initializable(footerHeading, mixin.footerHeading(), DEFAULT_SINGLE_VALUE))                         {footerHeading = mixin.footerHeading();}
 5095                if (initializable(parameterListHeading, mixin.parameterListHeading(), DEFAULT_SINGLE_VALUE))           {parameterListHeading = mixin.parameterListHeading();}
 5096                if (initializable(optionListHeading, mixin.optionListHeading(), DEFAULT_SINGLE_VALUE))                 {optionListHeading = mixin.optionListHeading();}
 5097                if (Messages.empty(messages)) { messages(Messages.copy(commandSpec, mixin.messages())); }
 5098            }
 5099            void initFrom(UsageMessageSpec settings, CommandSpec commandSpec) {
 5100                description = settings.description;
 5101                customSynopsis = settings.customSynopsis;
 5102                header = settings.header;
 5103                footer = settings.footer;
 5104                abbreviateSynopsis = settings.abbreviateSynopsis;
 5105                sortOptions = settings.sortOptions;
 5106                showDefaultValues = settings.showDefaultValues;
 5107                hidden = settings.hidden;
 5108                requiredOptionMarker = settings.requiredOptionMarker;
 5109                headerHeading = settings.headerHeading;
 5110                synopsisHeading = settings.synopsisHeading;
 5111                descriptionHeading = settings.descriptionHeading;
 5112                parameterListHeading = settings.parameterListHeading;
 5113                optionListHeading = settings.optionListHeading;
 5114                commandListHeading = settings.commandListHeading;
 5115                footerHeading = settings.footerHeading;
 5116                width = settings.width;
 5117                messages = Messages.copy(commandSpec, settings.messages());
 5118            }
 5119        }
 5120        /** Models parser configuration specification.
 5121         * @since 3.0 */
 5122        public static class ParserSpec {
 5123
 5124            /** Constant String holding the default separator between options and option parameters: <code>{@value}</code>.*/
 5125            static final String DEFAULT_SEPARATOR = "=";
 5126            private String separator;
 5127            private boolean stopAtUnmatched = false;
 5128            private boolean stopAtPositional = false;
 5129            private String endOfOptionsDelimiter = "--";
 5130            private boolean toggleBooleanFlags = true;
 5131            private boolean overwrittenOptionsAllowed = false;
 5132            private boolean unmatchedArgumentsAllowed = false;
 5133            private boolean expandAtFiles = true;
 5134            private boolean useSimplifiedAtFiles = false;
 5135            private Character atFileCommentChar = '#';
 5136            private boolean posixClusteredShortOptionsAllowed = true;
 5137            private boolean unmatchedOptionsArePositionalParams = false;
 5138            private boolean limitSplit = false;
 5139            private boolean aritySatisfiedByAttachedOptionParam = false;
 5140            private boolean collectErrors = false;
 5141            private boolean caseInsensitiveEnumValuesAllowed = false;
 5142            private boolean trimQuotes = shouldTrimQuotes();
 5143            private boolean splitQuotedStrings = false;
 5144
 5145            /** Returns the String to use as the separator between options and option parameters. {@code "="} by default,
 5146             * initialized from {@link Command#separator()} if defined.*/
 5147            public String separator() { return (separator == null) ? DEFAULT_SEPARATOR : separator; }
 5148
 5149            /** @see CommandLine#isStopAtUnmatched() */
 5150            public boolean stopAtUnmatched()                   { return stopAtUnmatched; }
 5151            /** @see CommandLine#isStopAtPositional() */
 5152            public boolean stopAtPositional()                  { return stopAtPositional; }
 5153            /** @see CommandLine#getEndOfOptionsDelimiter()
 5154             * @since 3.5 */
 5155            public String endOfOptionsDelimiter()             { return endOfOptionsDelimiter; }
 5156            /** @see CommandLine#isToggleBooleanFlags() */
 5157            public boolean toggleBooleanFlags()                { return toggleBooleanFlags; }
 5158            /** @see CommandLine#isOverwrittenOptionsAllowed() */
 5159            public boolean overwrittenOptionsAllowed()         { return overwrittenOptionsAllowed; }
 5160            /** @see CommandLine#isUnmatchedArgumentsAllowed() */
 5161            public boolean unmatchedArgumentsAllowed()         { return unmatchedArgumentsAllowed; }
 5162            /** @see CommandLine#isExpandAtFiles() */
 5163            public boolean expandAtFiles()                     { return expandAtFiles; }
 5164            /** @see CommandLine#getAtFileCommentChar()
 5165             * @since 3.5 */
 5166            public Character atFileCommentChar()               { return atFileCommentChar; }
 5167            /** @see CommandLine#isUseSimplifiedAtFiles()
 5168             * @since 3.9 */
 5169            public boolean useSimplifiedAtFiles()              {
 5170                String value = System.getProperty("picocli.useSimplifiedAtFiles");
 5171                if (value != null) {
 5172                    return "".equals(value) || Boolean.valueOf(value);
 5173                }
 5174                return useSimplifiedAtFiles;
 5175            }
 5176            /** @see CommandLine#isPosixClusteredShortOptionsAllowed() */
 5177            public boolean posixClusteredShortOptionsAllowed() { return posixClusteredShortOptionsAllowed; }
 5178            /** @see CommandLine#isCaseInsensitiveEnumValuesAllowed()
 5179             * @since 3.4 */
 5180            public boolean caseInsensitiveEnumValuesAllowed()  { return caseInsensitiveEnumValuesAllowed; }
 5181            /** @see CommandLine#isTrimQuotes()
 5182             * @since 3.7 */
 5183            public boolean trimQuotes()  { return trimQuotes; }
 5184            /** @see CommandLine#isSplitQuotedStrings()
 5185             * @since 3.7 */
 5186            public boolean splitQuotedStrings()  { return splitQuotedStrings; }
 5187            /** @see CommandLine#isUnmatchedOptionsArePositionalParams() */
 5188            public boolean unmatchedOptionsArePositionalParams() { return unmatchedOptionsArePositionalParams; }
 5189            private boolean splitFirst()                       { return limitSplit(); }
 5190            /** Returns true if arguments should be split first before any further processing and the number of
 5191             * parts resulting from the split is limited to the max arity of the argument. */
 5192            public boolean limitSplit()                        { return limitSplit; }
 5193            /** Returns true if options with attached arguments should not consume subsequent arguments and should not validate arity. The default is {@code false}. */
 5194            public boolean aritySatisfiedByAttachedOptionParam() { return aritySatisfiedByAttachedOptionParam; }
 5195            /** Returns true if exceptions during parsing should be collected instead of thrown.
 5196             * Multiple errors may be encountered during parsing. These can be obtained from {@link ParseResult#errors()}.
 5197             * @since 3.2 */
 5198            public boolean collectErrors()                     { return collectErrors; }
 5199
 5200            /** Sets the String to use as the separator between options and option parameters.
 5201             * @return this ParserSpec for method chaining */
 5202            public ParserSpec separator(String separator)                                  { this.separator = separator; return this; }
 5203            /** @see CommandLine#setStopAtUnmatched(boolean) */
 5204            public ParserSpec stopAtUnmatched(boolean stopAtUnmatched)                     { this.stopAtUnmatched = stopAtUnmatched; return this; }
 5205            /** @see CommandLine#setStopAtPositional(boolean) */
 5206            public ParserSpec stopAtPositional(boolean stopAtPositional)                   { this.stopAtPositional = stopAtPositional; return this; }
 5207            /** @see CommandLine#setEndOfOptionsDelimiter(String)
 5208             * @since 3.5 */
 5209            public ParserSpec endOfOptionsDelimiter(String delimiter)                      { this.endOfOptionsDelimiter = Assert.notNull(delimiter, "end-of-options delimiter"); return this; }
 5210            /** @see CommandLine#setToggleBooleanFlags(boolean) */
 5211            public ParserSpec toggleBooleanFlags(boolean toggleBooleanFlags)               { this.toggleBooleanFlags = toggleBooleanFlags; return this; }
 5212            /** @see CommandLine#setOverwrittenOptionsAllowed(boolean) */
 5213            public ParserSpec overwrittenOptionsAllowed(boolean overwrittenOptionsAllowed) { this.overwrittenOptionsAllowed = overwrittenOptionsAllowed; return this; }
 5214            /** @see CommandLine#setUnmatchedArgumentsAllowed(boolean) */
 5215            public ParserSpec unmatchedArgumentsAllowed(boolean unmatchedArgumentsAllowed) { this.unmatchedArgumentsAllowed = unmatchedArgumentsAllowed; return this; }
 5216            /** @see CommandLine#setExpandAtFiles(boolean) */
 5217            public ParserSpec expandAtFiles(boolean expandAtFiles)                         { this.expandAtFiles = expandAtFiles; return this; }
 5218            /** @see CommandLine#setAtFileCommentChar(Character)
 5219             * @since 3.5 */
 5220            public ParserSpec atFileCommentChar(Character atFileCommentChar)               { this.atFileCommentChar = atFileCommentChar; return this; }
 5221            /** @see CommandLine#setUseSimplifiedAtFiles(boolean)
 5222             * @since 3.9 */
 5223            public ParserSpec useSimplifiedAtFiles(boolean useSimplifiedAtFiles)           { this.useSimplifiedAtFiles = useSimplifiedAtFiles; return this; }
 5224            /** @see CommandLine#setPosixClusteredShortOptionsAllowed(boolean) */
 5225            public ParserSpec posixClusteredShortOptionsAllowed(boolean posixClusteredShortOptionsAllowed) { this.posixClusteredShortOptionsAllowed = posixClusteredShortOptionsAllowed; return this; }
 5226            /** @see CommandLine#setCaseInsensitiveEnumValuesAllowed(boolean)
 5227             * @since 3.4 */
 5228            public ParserSpec caseInsensitiveEnumValuesAllowed(boolean caseInsensitiveEnumValuesAllowed) { this.caseInsensitiveEnumValuesAllowed = caseInsensitiveEnumValuesAllowed; return this; }
 5229            /** @see CommandLine#setTrimQuotes(boolean)
 5230             * @since 3.7 */
 5231            public ParserSpec trimQuotes(boolean trimQuotes) { this.trimQuotes = trimQuotes; return this; }
 5232            /** @see CommandLine#setSplitQuotedStrings(boolean)
 5233             * @since 3.7 */
 5234            public ParserSpec splitQuotedStrings(boolean splitQuotedStrings)  { this.splitQuotedStrings = splitQuotedStrings; return this; }
 5235            /** @see CommandLine#setUnmatchedOptionsArePositionalParams(boolean) */
 5236            public ParserSpec unmatchedOptionsArePositionalParams(boolean unmatchedOptionsArePositionalParams) { this.unmatchedOptionsArePositionalParams = unmatchedOptionsArePositionalParams; return this; }
 5237            /** Sets whether exceptions during parsing should be collected instead of thrown.
 5238             * Multiple errors may be encountered during parsing. These can be obtained from {@link ParseResult#errors()}.
 5239             * @since 3.2 */
 5240            public ParserSpec collectErrors(boolean collectErrors)                         { this.collectErrors = collectErrors; return this; }
 5241
 5242            /** Returns true if options with attached arguments should not consume subsequent arguments and should not validate arity. The default is {@code false}.*/
 5243            public ParserSpec aritySatisfiedByAttachedOptionParam(boolean newValue) { aritySatisfiedByAttachedOptionParam = newValue; return this; }
 5244
 5245            /** Sets whether arguments should be {@linkplain ArgSpec#splitRegex() split} first before any further processing.
 5246             * If true, the original argument will only be split into as many parts as allowed by max arity. */
 5247            public ParserSpec limitSplit(boolean limitSplit)                               { this.limitSplit = limitSplit; return this; }
 5248
 5249            private boolean shouldTrimQuotes() {
 5250                String value = System.getProperty("picocli.trimQuotes");
 5251                if ("".equals(value)) { value = "true"; }
 5252                return Boolean.valueOf(value);
 5253            }
 5254
 5255            void initSeparator(String value)   { if (initializable(separator, value, DEFAULT_SEPARATOR)) {separator = value;} }
 5256            void updateSeparator(String value) { if (isNonDefault(value, DEFAULT_SEPARATOR))             {separator = value;} }
 5257            public String toString() {
 5258                return String.format("posixClusteredShortOptionsAllowed=%s, stopAtPositional=%s, stopAtUnmatched=%s, " +
 5259                                "separator=%s, overwrittenOptionsAllowed=%s, unmatchedArgumentsAllowed=%s, expandAtFiles=%s, " +
 5260                                "atFileCommentChar=%s, useSimplifiedAtFiles=%s, endOfOptionsDelimiter=%s, limitSplit=%s, aritySatisfiedByAttachedOptionParam=%s, " +
 5261                                "toggleBooleanFlags=%s, unmatchedOptionsArePositionalParams=%s, collectErrors=%s," +
 5262                                "caseInsensitiveEnumValuesAllowed=%s, trimQuotes=%s, splitQuotedStrings=%s",
 5263                        posixClusteredShortOptionsAllowed, stopAtPositional, stopAtUnmatched,
 5264                        separator, overwrittenOptionsAllowed, unmatchedArgumentsAllowed, expandAtFiles,
 5265                        atFileCommentChar, useSimplifiedAtFiles, endOfOptionsDelimiter, limitSplit, aritySatisfiedByAttachedOptionParam,
 5266                        toggleBooleanFlags, unmatchedOptionsArePositionalParams, collectErrors,
 5267                        caseInsensitiveEnumValuesAllowed, trimQuotes, splitQuotedStrings);
 5268            }
 5269
 5270            void initFrom(ParserSpec settings) {
 5271                separator = settings.separator;
 5272                stopAtUnmatched = settings.stopAtUnmatched;
 5273                stopAtPositional = settings.stopAtPositional;
 5274                endOfOptionsDelimiter = settings.endOfOptionsDelimiter;
 5275                toggleBooleanFlags = settings.toggleBooleanFlags;
 5276                overwrittenOptionsAllowed = settings.overwrittenOptionsAllowed;
 5277                unmatchedArgumentsAllowed = settings.unmatchedArgumentsAllowed;
 5278                expandAtFiles = settings.expandAtFiles;
 5279                atFileCommentChar = settings.atFileCommentChar;
 5280                posixClusteredShortOptionsAllowed = settings.posixClusteredShortOptionsAllowed;
 5281                unmatchedOptionsArePositionalParams = settings.unmatchedOptionsArePositionalParams;
 5282                limitSplit = settings.limitSplit;
 5283                aritySatisfiedByAttachedOptionParam = settings.aritySatisfiedByAttachedOptionParam;
 5284                collectErrors = settings.collectErrors;
 5285                caseInsensitiveEnumValuesAllowed = settings.caseInsensitiveEnumValuesAllowed;
 5286                trimQuotes = settings.trimQuotes;
 5287                splitQuotedStrings = settings.splitQuotedStrings;
 5288            }
 5289        }
 5290        /** Models the shared attributes of {@link OptionSpec} and {@link PositionalParamSpec}.
 5291         * @since 3.0 */
 5292        public abstract static class ArgSpec {
 5293            static final String DESCRIPTION_VARIABLE_DEFAULT_VALUE = "${DEFAULT-VALUE}";
 5294            static final String DESCRIPTION_VARIABLE_COMPLETION_CANDIDATES = "${COMPLETION-CANDIDATES}";
 5295            private static final String NO_DEFAULT_VALUE = "__no_default_value__";
 5296
 5297            // help-related fields
 5298            private final boolean hidden;
 5299            private final String paramLabel;
 5300            private final boolean hideParamSyntax;
 5301            private final String[] description;
 5302            private final String descriptionKey;
 5303            private final Help.Visibility showDefaultValue;
 5304            private Messages messages;
 5305            CommandSpec commandSpec;
 5306            private ArgGroupSpec group;
 5307            private final Object userObject;
 5308
 5309            // parser fields
 5310            private final boolean interactive;
 5311            private final boolean required;
 5312            private final String splitRegex;
 5313            private final ITypeInfo typeInfo;
 5314            private final ITypeConverter<?>[] converters;
 5315            private final Iterable<String> completionCandidates;
 5316            private final String defaultValue;
 5317            private final Object initialValue;
 5318            private final boolean hasInitialValue;
 5319            private final IGetter getter;
 5320            private final ISetter setter;
 5321            private final IScope scope;
 5322            private final Range arity;
 5323            private List<String> stringValues = new ArrayList<String>();
 5324            private List<String> originalStringValues = new ArrayList<String>();
 5325            protected String toString;
 5326            private List<Object> typedValues = new ArrayList<Object>();
 5327            Map<Integer, Object> typedValueAtPosition = new TreeMap<Integer, Object>();
 5328
 5329            /** Constructs a new {@code ArgSpec}. */
 5330            private <T extends Builder<T>> ArgSpec(Builder<T> builder) {
 5331                userObject = builder.userObject;
 5332                description = builder.description == null ? new String[0] : builder.description;
 5333                descriptionKey = builder.descriptionKey;
 5334                splitRegex = builder.splitRegex == null ? "" : builder.splitRegex;
 5335                paramLabel = empty(builder.paramLabel) ? "PARAM" : builder.paramLabel;
 5336                hideParamSyntax = builder.hideParamSyntax;
 5337                converters = builder.converters == null ? new ITypeConverter<?>[0] : builder.converters;
 5338                showDefaultValue = builder.showDefaultValue == null ? Help.Visibility.ON_DEMAND : builder.showDefaultValue;
 5339                hidden = builder.hidden;
 5340                interactive = builder.interactive;
 5341                initialValue = builder.initialValue;
 5342                hasInitialValue = builder.hasInitialValue;
 5343                defaultValue = NO_DEFAULT_VALUE.equals(builder.defaultValue) ? null : builder.defaultValue;
 5344                required = builder.required && defaultValue == null; //#261 not required if it has a default
 5345                toString = builder.toString;
 5346                getter = builder.getter;
 5347                setter = builder.setter;
 5348                scope  = builder.scope;
 5349
 5350                Range tempArity = builder.arity;
 5351                if (tempArity == null) {
 5352                    if (isOption()) {
 5353                        tempArity = (builder.type == null || isBoolean(builder.type)) ? Range.valueOf("0") : Range.valueOf("1");
 5354                    } else {
 5355                        tempArity = Range.valueOf("1");
 5356                    }
 5357                    tempArity = tempArity.unspecified(true);
 5358                }
 5359                arity = tempArity;
 5360
 5361                if (builder.typeInfo == null) {
 5362                    this.typeInfo = RuntimeTypeInfo.create(builder.type, builder.auxiliaryTypes,
 5363                            Collections.<String>emptyList(), arity, (isOption() ? boolean.class : String.class));
 5364                } else {
 5365                    this.typeInfo = builder.typeInfo;
 5366                }
 5367
 5368                if (builder.completionCandidates == null && typeInfo.isEnum()) {
 5369                    List<String> list = new ArrayList<String>();
 5370                    for (Object c : typeInfo.getEnumConstantNames()) { list.add(c.toString()); }
 5371                    completionCandidates = Collections.unmodifiableList(list);
 5372                } else {
 5373                    completionCandidates = builder.completionCandidates;
 5374                }
 5375                if (interactive && (arity.min != 1 || arity.max != 1)) {
 5376                    throw new InitializationException("Interactive options and positional parameters are only supported for arity=1, not for arity=" + arity);
 5377                }
 5378            }
 5379            void applyInitialValue(Tracer tracer) {
 5380                if (hasInitialValue()) {
 5381                    try {
 5382                        setter().set(initialValue());
 5383                        tracer.debug("Set initial value for %s of type %s to %s.%n", this, type(), String.valueOf(initialValue()));
 5384                    } catch (Exception ex) {
 5385                        tracer.warn("Could not set initial value for %s of type %s to %s: %s%n", this, type(), String.valueOf(initialValue()), ex);
 5386                    }
 5387                } else {
 5388                    tracer.debug("Initial value not available for %s%n", this);
 5389                }
 5390            }
 5391
 5392            /** Returns whether this is a required option or positional parameter.
 5393             * 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).
 5394             * @see Option#required() */
 5395            public boolean required()      { return required; }
 5396
 5397            /** Returns whether this option will prompt the user to enter a value on the command line.
 5398             * @see Option#interactive() */
 5399            public boolean interactive()   { return interactive; }
 5400
 5401            /** Returns the description template of this option, before variables are rendered.
 5402             * @see Option#description() */
 5403            public String[] description()  { return description.clone(); }
 5404
 5405            /** Returns the description key of this arg spec, used to get the description from a resource bundle.
 5406             * @see Option#descriptionKey()
 5407             * @see Parameters#descriptionKey()
 5408             * @since 3.6 */
 5409            public String descriptionKey()  { return descriptionKey; }
 5410
 5411            /** Returns the description of this option, after variables are rendered. Used when generating the usage documentation.
 5412             * @see Option#description()
 5413             * @since 3.2 */
 5414            public String[] renderedDescription()  {
 5415                String[] desc = description();
 5416                if (desc.length == 0) { return desc; }
 5417                StringBuilder candidates = new StringBuilder();
 5418                if (completionCandidates() != null) {
 5419                    for (String c : completionCandidates()) {
 5420                        if (candidates.length() > 0) { candidates.append(", "); }
 5421                        candidates.append(c);
 5422                    }
 5423                }
 5424                String defaultValueString = defaultValueString();
 5425                String[] result = new String[desc.length];
 5426                for (int i = 0; i < desc.length; i++) {
 5427                    result[i] = format(desc[i].replace(DESCRIPTION_VARIABLE_DEFAULT_VALUE, defaultValueString.replace("%", "%%"))
 5428                            .replace(DESCRIPTION_VARIABLE_COMPLETION_CANDIDATES, candidates.toString()));
 5429                }
 5430                return result;
 5431            }
 5432
 5433            /** Returns how many arguments this option or positional parameter requires.
 5434             * @see Option#arity() */
 5435            public Range arity()           { return arity; }
 5436    
 5437            /** Returns the name of the option or positional parameter used in the usage help message.
 5438             * @see Option#paramLabel() {@link Parameters#paramLabel()} */
 5439            public String paramLabel()     { return paramLabel; }
 5440    
 5441            /** Returns whether usage syntax decorations around the {@linkplain #paramLabel() paramLabel} should be suppressed.
 5442             * The default is {@code false}: by default, the paramLabel is surrounded with {@code '['} and {@code ']'} characters
 5443             * if the value is optional and followed by ellipses ("...") when multiple values can be specified.
 5444             * @since 3.6.0 */
 5445            public boolean hideParamSyntax()     { return hideParamSyntax; }
 5446    
 5447            /** Returns auxiliary type information used when the {@link #type()} is a generic {@code Collection}, {@code Map} or an abstract class.
 5448             * @see Option#type() */
 5449            public Class<?>[] auxiliaryTypes() { return typeInfo.getAuxiliaryTypes(); }
 5450    
 5451            /** Returns one or more {@link CommandLine.ITypeConverter type converters} to use to convert the command line
 5452             * argument into a strongly typed value (or key-value pair for map fields). This is useful when a particular
 5453             * option or positional parameter should use a custom conversion that is different from the normal conversion for the arg spec's type.
 5454             * @see Option#converter() */
 5455            public ITypeConverter<?>[] converters() { return converters.clone(); }
 5456    
 5457            /** Returns a regular expression to split option parameter values or {@code ""} if the value should not be split.
 5458             * @see Option#split() */
 5459            public String splitRegex()     { return splitRegex; }
 5460    
 5461            /** Returns whether this option should be excluded from the usage message.
 5462             * @see Option#hidden() */
 5463            public boolean hidden()        { return hidden; }
 5464    
 5465            /** Returns the type to convert the option or positional parameter to before {@linkplain #setValue(Object) setting} the value. */
 5466            public Class<?> type()         { return typeInfo.getType(); }
 5467
 5468            /** Returns the {@code ITypeInfo} that can be used both at compile time (by annotation processors) and at runtime.
 5469             * @since 4.0 */
 5470            public ITypeInfo typeInfo()    { return typeInfo; }
 5471
 5472            /** Returns the user object associated with this option or positional parameters.
 5473             * @return may return the annotated program element, or some other useful object
 5474             * @since 4.0 */
 5475            public Object userObject()     { return userObject; }
 5476    
 5477            /** Returns the default value of this option or positional parameter, before splitting and type conversion.
 5478             * This method returns the programmatically set value; this may differ from the default value that is actually used:
 5479             * if this ArgSpec is part of a CommandSpec with a {@link IDefaultValueProvider}, picocli will first try to obtain
 5480             * the default value from the default value provider, and this method is only called if the default provider is
 5481             * {@code null} or returned a {@code null} value.
 5482             * @return the programmatically set default value of this option/positional parameter,
 5483             *      returning {@code null} means this option or positional parameter does not have a default
 5484             * @see CommandSpec#defaultValueProvider()
 5485             */
 5486            public String defaultValue()   { return defaultValue; }
 5487            /** Returns the initial value this option or positional parameter. If {@link #hasInitialValue()} is true,
 5488             * the option will be reset to the initial value before parsing (regardless of whether a default value exists),
 5489             * to clear values that would otherwise remain from parsing previous input. */
 5490            public Object initialValue()     { return initialValue; }
 5491            /** Determines whether the option or positional parameter will be reset to the {@link #initialValue()}
 5492             * before parsing new input.*/
 5493            public boolean hasInitialValue() { return hasInitialValue; }
 5494    
 5495            /** Returns whether this option or positional parameter's default value should be shown in the usage help. */
 5496            public Help.Visibility showDefaultValue() { return showDefaultValue; }
 5497
 5498            /** Returns the default value String displayed in the description. If this ArgSpec is part of a
 5499             * CommandSpec with a {@link IDefaultValueProvider}, this method will first try to obtain
 5500             * the default value from the default value provider; if the provider is {@code null} or if it
 5501             * returns a {@code null} value, then next any value set to {@link ArgSpec#defaultValue()}
 5502             * is returned, and if this is also {@code null}, finally the {@linkplain ArgSpec#initialValue() initial value} is returned.
 5503             * @see CommandSpec#defaultValueProvider()
 5504             * @see ArgSpec#defaultValue() */
 5505            public String defaultValueString() {
 5506                String fromProvider = defaultValueFromProvider();
 5507                String defaultVal = fromProvider == null ? this.defaultValue() : fromProvider;
 5508                Object value = defaultVal == null ? initialValue() : defaultVal;
 5509                if (value != null && value.getClass().isArray()) {
 5510                    StringBuilder sb = new StringBuilder();
 5511                    for (int i = 0; i < Array.getLength(value); i++) {
 5512                        sb.append(i > 0 ? ", " : "").append(Array.get(value, i));
 5513                    }
 5514                    return sb.insert(0, "[").append("]").toString();
 5515                }
 5516                return String.valueOf(value);
 5517            }
 5518
 5519            private String defaultValueFromProvider() {
 5520                String fromProvider = null;
 5521                IDefaultValueProvider defaultValueProvider = null;
 5522                try {
 5523                    defaultValueProvider = commandSpec.defaultValueProvider();
 5524                    fromProvider = defaultValueProvider == null ? null : defaultValueProvider.defaultValue(this);
 5525                } catch (Exception ex) {
 5526                    new Tracer().info("Error getting default value for %s from %s: %s", this, defaultValueProvider, ex);
 5527                }
 5528                return fromProvider;
 5529            }
 5530
 5531            /** Returns the explicitly set completion candidates for this option or positional parameter, valid enum
 5532             * constant names, or {@code null} if this option or positional parameter does not have any completion
 5533             * candidates and its type is not an enum.
 5534             * @return the completion candidates for this option or positional parameter, valid enum constant names,
 5535             * or {@code null}
 5536             * @since 3.2 */
 5537            public Iterable<String> completionCandidates() { return completionCandidates; }
 5538
 5539            /** Returns the {@link IGetter} that is responsible for supplying the value of this argument. */
 5540            public IGetter getter()        { return getter; }
 5541            /** Returns the {@link ISetter} that is responsible for modifying the value of this argument. */
 5542            public ISetter setter()        { return setter; }
 5543            /** Returns the {@link IScope} that determines on which object to set the value (or from which object to get the value) of this argument. */
 5544            public IScope scope()          { return scope; }
 5545
 5546            /** Returns the current value of this argument. Delegates to the current {@link #getter()}. */
 5547            public <T> T getValue() throws PicocliException {
 5548                try {
 5549                    return getter.get();
 5550                } catch (PicocliException ex) { throw ex;
 5551                } catch (Exception ex) {        throw new PicocliException("Could not get value for " + this + ": " + ex, ex);
 5552                }
 5553            }
 5554            /** Sets the value of this argument to the specified value and returns the previous value. Delegates to the current {@link #setter()}. */
 5555            public <T> T setValue(T newValue) throws PicocliException {
 5556                try {
 5557                    return setter.set(newValue);
 5558                } catch (PicocliException ex) { throw ex;
 5559                } catch (Exception ex) {        throw new PicocliException("Could not set value (" + newValue + ") for " + this + ": " + ex, ex);
 5560                }
 5561            }
 5562            /** Sets the value of this argument to the specified value and returns the previous value. Delegates to the current {@link #setter()}.
 5563             * @deprecated use {@link #setValue(Object)} instead. This was a design mistake.
 5564             * @since 3.5 */
 5565            @Deprecated public <T> T setValue(T newValue, CommandLine commandLine) throws PicocliException {
 5566                return setValue(newValue);
 5567            }
 5568
 5569            /** Returns {@code true} if this argument's {@link #type()} is an array, a {@code Collection} or a {@code Map}, {@code false} otherwise. */
 5570            public boolean isMultiValue()     { return typeInfo.isMultiValue(); }
 5571            /** Returns {@code true} if this argument is a named option, {@code false} otherwise. */
 5572            public abstract boolean isOption();
 5573            /** Returns {@code true} if this argument is a positional parameter, {@code false} otherwise. */
 5574            public abstract boolean isPositional();
 5575
 5576            /** Returns the groups this option or positional parameter belongs to, or {@code null} if this option is not part of a group.
 5577             * @since 4.0 */
 5578            public ArgGroupSpec group() { return group; }
 5579
 5580            /** Returns the untyped command line arguments matched by this option or positional parameter spec.
 5581             * @return the matched arguments after {@linkplain #splitRegex() splitting}, but before type conversion.
 5582             *      For map properties, {@code "key=value"} values are split into the key and the value part. */
 5583            public List<String> stringValues() { return Collections.unmodifiableList(stringValues); }
 5584
 5585            /** Returns the typed command line arguments matched by this option or positional parameter spec.
 5586             * @return the matched arguments after {@linkplain #splitRegex() splitting} and type conversion.
 5587             *      For map properties, {@code "key=value"} values are split into the key and the value part. */
 5588            public List<Object> typedValues() { return Collections.unmodifiableList(typedValues); }
 5589
 5590            /** Sets the {@code stringValues} to a new list instance. */
 5591            protected void resetStringValues() { stringValues = new ArrayList<String>(); }
 5592
 5593            /** Returns the original command line arguments matched by this option or positional parameter spec.
 5594             * @return the matched arguments as found on the command line: empty Strings for options without value, the
 5595             *      values have not been {@linkplain #splitRegex() split}, and for map properties values may look like {@code "key=value"}*/
 5596            public List<String> originalStringValues() { return Collections.unmodifiableList(originalStringValues); }
 5597
 5598            /** Sets the {@code originalStringValues} to a new list instance. */
 5599            protected void resetOriginalStringValues() { originalStringValues = new ArrayList<String>(); }
 5600
 5601            /** Returns whether the default for this option or positional parameter should be shown, potentially overriding the specified global setting.
 5602             * @param usageHelpShowDefaults whether the command's UsageMessageSpec is configured to show default values. */
 5603            protected boolean internalShowDefaultValue(boolean usageHelpShowDefaults) {
 5604                if (showDefaultValue() == Help.Visibility.ALWAYS)   { return true; }  // override global usage help setting
 5605                if (showDefaultValue() == Help.Visibility.NEVER)    { return false; } // override global usage help setting
 5606                if (initialValue == null && defaultValue() == null && defaultValueFromProvider() == null) { return false; } // no default value to show
 5607                return usageHelpShowDefaults && !isBoolean(type());
 5608            }
 5609            /** Returns the Messages for this arg specification, or {@code null}.
 5610             * @since 3.6 */
 5611            public Messages messages() { return messages; }
 5612            /** Sets the Messages for this ArgSpec, and returns this ArgSpec.
 5613             * @param msgs the new Messages value, may be {@code null}
 5614             * @see Command#resourceBundle()
 5615             * @see OptionSpec#description()
 5616             * @see PositionalParamSpec#description()
 5617             * @since 3.6 */
 5618            public ArgSpec messages(Messages msgs) { messages = msgs; return this; }
 5619
 5620            /** Returns a string respresentation of this option or positional parameter. */
 5621            public String toString() { return toString; }
 5622    
 5623            String[] splitValue(String value, ParserSpec parser, Range arity, int consumed) {
 5624                if (splitRegex().length() == 0) { return new String[] {value}; }
 5625                int limit = parser.limitSplit() ? Math.max(arity.max - consumed, 0) : 0;
 5626                if (parser.splitQuotedStrings()) {
 5627                    return debug(value.split(splitRegex(), limit), "Split (ignoring quotes)", value);
 5628                }
 5629                return debug(splitRespectingQuotedStrings(value, limit, parser, this, splitRegex()), "Split", value);
 5630            }
 5631            private String[] debug(String[] result, String msg, String value) {
 5632                Tracer t = new Tracer();
 5633                if (t.isDebug()) {t.debug("%s with regex '%s' resulted in %s parts: %s%n", msg, splitRegex(), result.length, Arrays.asList(result));}
 5634                return result;
 5635            }
 5636            // @since 3.7
 5637            private static String[] splitRespectingQuotedStrings(String value, int limit, ParserSpec parser, ArgSpec argSpec, String splitRegex) {
 5638                StringBuilder splittable = new StringBuilder();
 5639                StringBuilder temp = new StringBuilder();
 5640                StringBuilder current = splittable;
 5641                Queue<String> quotedValues = new LinkedList<String>();
 5642                boolean escaping = false, inQuote = false;
 5643                for (int ch = 0, i = 0; i < value.length(); i += Character.charCount(ch)) {
 5644                    ch = value.codePointAt(i);
 5645                    switch (ch) {
 5646                        case '\\': escaping = !escaping; break;
 5647                        case '\"':
 5648                            if (!escaping) {
 5649                                inQuote = !inQuote;
 5650                                current = inQuote ? temp : splittable;
 5651                                if (inQuote) {
 5652                                    splittable.appendCodePoint(ch);
 5653                                    continue;
 5654                                } else {
 5655                                    quotedValues.add(temp.toString());
 5656                                    temp.setLength(0);
 5657                                }
 5658                            }
 5659                            break;
 5660                        default: escaping = false; break;
 5661                    }
 5662                    current.appendCodePoint(ch);
 5663                }
 5664                if (temp.length() > 0) {
 5665                    new Tracer().warn("Unbalanced quotes in [%s] for %s (value=%s)%n", temp, argSpec, value);
 5666                    quotedValues.add(temp.toString());
 5667                    temp.setLength(0);
 5668                }
 5669                String[] result = splittable.toString().split(splitRegex, limit);
 5670                for (int i = 0; i < result.length; i++) {
 5671                    result[i] = restoreQuotedValues(result[i], quotedValues, parser);
 5672                }
 5673                if (!quotedValues.isEmpty()) {
 5674                    new Tracer().warn("Unable to respect quotes while splitting value %s for %s (unprocessed remainder: %s)%n", value, argSpec, quotedValues);
 5675                    return value.split(splitRegex, limit);
 5676                }
 5677                return result;
 5678            }
 5679
 5680            private static String restoreQuotedValues(String part, Queue<String> quotedValues, ParserSpec parser) {
 5681                StringBuilder result = new StringBuilder();
 5682                boolean escaping = false, inQuote = false, skip = false;
 5683                for (int ch = 0, i = 0; i < part.length(); i += Character.charCount(ch)) {
 5684                    ch = part.codePointAt(i);
 5685                    switch (ch) {
 5686                        case '\\': escaping = !escaping; break;
 5687                        case '\"':
 5688                            if (!escaping) {
 5689                                inQuote = !inQuote;
 5690                                if (!inQuote) { result.append(quotedValues.remove()); }
 5691                                skip = parser.trimQuotes();
 5692                            }
 5693                            break;
 5694                        default: escaping = false; break;
 5695                    }
 5696                    if (!skip) { result.appendCodePoint(ch); }
 5697                    skip = false;
 5698                }
 5699                return result.toString();
 5700            }
 5701
 5702            protected boolean equalsImpl(ArgSpec other) {
 5703                boolean result = Assert.equals(this.defaultValue, other.defaultValue)
 5704                        && Assert.equals(this.arity, other.arity)
 5705                        && Assert.equals(this.hidden, other.hidden)
 5706                        && Assert.equals(this.paramLabel, other.paramLabel)
 5707                        && Assert.equals(this.hideParamSyntax, other.hideParamSyntax)
 5708                        && Assert.equals(this.required, other.required)
 5709                        && Assert.equals(this.splitRegex, other.splitRegex)
 5710                        && Arrays.equals(this.description, other.description)
 5711                        && Assert.equals(this.descriptionKey, other.descriptionKey)
 5712                        && this.typeInfo.equals(other.typeInfo)
 5713                        ;
 5714                return result;
 5715            }
 5716            protected int hashCodeImpl() {
 5717                return 17
 5718                        + 37 * Assert.hashCode(defaultValue)
 5719                        + 37 * Assert.hashCode(arity)
 5720                        + 37 * Assert.hashCode(hidden)
 5721                        + 37 * Assert.hashCode(paramLabel)
 5722                        + 37 * Assert.hashCode(hideParamSyntax)
 5723                        + 37 * Assert.hashCode(required)
 5724                        + 37 * Assert.hashCode(splitRegex)
 5725                        + 37 * Arrays.hashCode(description)
 5726                        + 37 * Assert.hashCode(descriptionKey)
 5727                        + 37 * typeInfo.hashCode()
 5728                        ;
 5729            }
 5730
 5731            private static String describe(Collection<ArgSpec> args) {
 5732                StringBuilder sb = new StringBuilder();
 5733                for (ArgSpec arg : args) {
 5734                    if (sb.length() > 0) { sb.append(", "); }
 5735                    sb.append(describe(arg, "="));
 5736                }
 5737                return sb.toString();
 5738            }
 5739            /** Returns a description of the option or positional arg, e.g. {@code -a=<a>}
 5740             * @param separator separator between arg and arg parameter label, usually '=' */
 5741            private static String describe(ArgSpec argSpec, String separator) {
 5742                return describe(argSpec, separator, argSpec.paramLabel());
 5743            }
 5744            /** Returns a description of the option or positional arg
 5745             * @param separator separator between arg and arg parameter value, usually '='
 5746             * @param value the value to append after the separator*/
 5747            private static String describe(ArgSpec argSpec, String separator, String value) {
 5748                String prefix = (argSpec.isOption())
 5749                        ? ((OptionSpec) argSpec).longestName()
 5750                        : "params[" + ((PositionalParamSpec) argSpec).index() + "]";
 5751                return argSpec.arity().min > 0 ? prefix + separator + value : prefix;
 5752            }
 5753            abstract static class Builder<T extends Builder<T>> {
 5754                private Object userObject;
 5755                private Range arity;
 5756                private String[] description;
 5757                private String descriptionKey;
 5758                private boolean required;
 5759                private boolean interactive;
 5760                private String paramLabel;
 5761                private boolean hideParamSyntax;
 5762                private String splitRegex;
 5763                private boolean hidden;
 5764                private Class<?> type;
 5765                private Class<?>[] auxiliaryTypes;
 5766                private ITypeInfo typeInfo;
 5767                private ITypeConverter<?>[] converters;
 5768                private String defaultValue;
 5769                private Object initialValue;
 5770                private boolean hasInitialValue = true;
 5771                private Help.Visibility showDefaultValue;
 5772                private Iterable<String> completionCandidates;
 5773                private String toString;
 5774                private IGetter getter = new ObjectBinding();
 5775                private ISetter setter = (ISetter) getter;
 5776                private IScope scope = new ObjectScope(null);
 5777
 5778                Builder() {}
 5779                Builder(ArgSpec original) {
 5780                    userObject = original.userObject;
 5781                    arity = original.arity;
 5782                    converters = original.converters;
 5783                    defaultValue = original.defaultValue;
 5784                    description = original.description;
 5785                    getter = original.getter;
 5786                    setter = original.setter;
 5787                    hidden = original.hidden;
 5788                    paramLabel = original.paramLabel;
 5789                    hideParamSyntax = original.hideParamSyntax;
 5790                    required = original.required;
 5791                    interactive = original.interactive;
 5792                    showDefaultValue = original.showDefaultValue;
 5793                    completionCandidates = original.completionCandidates;
 5794                    splitRegex = original.splitRegex;
 5795                    toString = original.toString;
 5796                    descriptionKey = original.descriptionKey;
 5797                    setTypeInfo(original.typeInfo);
 5798                }
 5799                Builder(IAnnotatedElement source) {
 5800                    userObject = source.userObject();
 5801                    setTypeInfo(source.getTypeInfo());
 5802                    toString = source.getToString();
 5803                    getter = source.getter();
 5804                    setter = source.setter();
 5805                    scope = source.scope();
 5806                    hasInitialValue = source.hasInitialValue();
 5807                    try { initialValue = source.getter().get(); } catch (Exception ex) { initialValue = null; hasInitialValue = false; }
 5808                }
 5809                Builder(Option option, IAnnotatedElement source, IFactory factory) {
 5810                    this(source);
 5811                    arity = Range.optionArity(source);
 5812                    required = option.required();
 5813
 5814                    paramLabel = inferLabel(option.paramLabel(), source.getName(), source.getTypeInfo());
 5815
 5816                    hideParamSyntax = option.hideParamSyntax();
 5817                    interactive = option.interactive();
 5818                    description = option.description();
 5819                    descriptionKey = option.descriptionKey();
 5820                    splitRegex = option.split();
 5821                    hidden = option.hidden();
 5822                    defaultValue = option.defaultValue();
 5823                    showDefaultValue = option.showDefaultValue();
 5824                    if (factory != null) {
 5825                        converters = DefaultFactory.createConverter(factory, option.converter());
 5826                        if (!NoCompletionCandidates.class.equals(option.completionCandidates())) {
 5827                            completionCandidates = DefaultFactory.createCompletionCandidates(factory, option.completionCandidates());
 5828                        }
 5829                    }
 5830                }
 5831                Builder(Parameters parameters, IAnnotatedElement source, IFactory factory) {
 5832                    this(source);
 5833                    arity = Range.parameterArity(source);
 5834                    required = arity.min > 0;
 5835
 5836                    // method parameters may be positional parameters without @Parameters annotation
 5837                    if (parameters == null) {
 5838                        paramLabel = inferLabel(null, source.getName(), source.getTypeInfo());
 5839                    } else {
 5840                        paramLabel = inferLabel(parameters.paramLabel(), source.getName(), source.getTypeInfo());
 5841
 5842                        hideParamSyntax = parameters.hideParamSyntax();
 5843                        interactive = parameters.interactive();
 5844                        description = parameters.description();
 5845                        descriptionKey = parameters.descriptionKey();
 5846                        splitRegex = parameters.split();
 5847                        hidden = parameters.hidden();
 5848                        defaultValue = parameters.defaultValue();
 5849                        showDefaultValue = parameters.showDefaultValue();
 5850                        if (factory != null) { // annotation processors will pass a null factory
 5851                            converters = DefaultFactory.createConverter(factory, parameters.converter());
 5852                            if (!NoCompletionCandidates.class.equals(parameters.completionCandidates())) {
 5853                                completionCandidates = DefaultFactory.createCompletionCandidates(factory, parameters.completionCandidates());
 5854                            }
 5855                        }
 5856                    }
 5857                }
 5858                private static String inferLabel(String label, String fieldName, ITypeInfo typeInfo) {
 5859                    if (!empty(label)) { return label.trim(); }
 5860                    String name = fieldName;
 5861                    if (typeInfo.isMap()) { // #195 better param labels for map fields
 5862                        List<ITypeInfo> aux = typeInfo.getAuxiliaryTypeInfos();
 5863                        if (aux.size() < 2 || aux.get(0) == null || aux.get(1) == null) {
 5864                            name = "String=String";
 5865                        } else { name = aux.get(0).getClassSimpleName() + "=" + aux.get(1).getClassSimpleName(); }
 5866                    }
 5867                    return "<" + name + ">";
 5868                }
 5869
 5870                public    abstract ArgSpec build();
 5871                protected abstract T self(); // subclasses must override to return "this"
 5872                /** Returns whether this is a required option or positional parameter.
 5873                 * @see Option#required() */
 5874                public boolean required()      { return required; }
 5875                /** Returns whether this option prompts the user to enter a value on the command line.
 5876                 * @see Option#interactive() */
 5877                public boolean interactive()   { return interactive; }
 5878
 5879                /** Returns the description of this option, used when generating the usage documentation.
 5880                 * @see Option#description() */
 5881                public String[] description()  { return description; }
 5882
 5883                /** Returns the description key of this arg spec, used to get the description from a resource bundle.
 5884                 * @see Option#descriptionKey()
 5885                 * @see Parameters#descriptionKey()
 5886                 * @since 3.6 */
 5887                public String descriptionKey()  { return descriptionKey; }
 5888
 5889                /** Returns how many arguments this option or positional parameter requires.
 5890                 * @see Option#arity() */
 5891                public Range arity()           { return arity; }
 5892    
 5893                /** Returns the name of the option or positional parameter used in the usage help message.
 5894                 * @see Option#paramLabel() {@link Parameters#paramLabel()} */
 5895                public String paramLabel()     { return paramLabel; }
 5896
 5897                /** Returns whether usage syntax decorations around the {@linkplain #paramLabel() paramLabel} should be suppressed.
 5898                 * The default is {@code false}: by default, the paramLabel is surrounded with {@code '['} and {@code ']'} characters
 5899                 * if the value is optional and followed by ellipses ("...") when multiple values can be specified.
 5900                 * @since 3.6.0 */
 5901                public boolean hideParamSyntax()     { return hideParamSyntax; }
 5902
 5903                /** Returns auxiliary type information used when the {@link #type()} is a generic {@code Collection}, {@code Map} or an abstract class.
 5904                 * @see Option#type() */
 5905                public Class<?>[] auxiliaryTypes() { return auxiliaryTypes; }
 5906
 5907                /** Returns one or more {@link CommandLine.ITypeConverter type converters} to use to convert the command line
 5908                 * argument into a strongly typed value (or key-value pair for map fields). This is useful when a particular
 5909                 * option or positional parameter should use a custom conversion that is different from the normal conversion for the arg spec's type.
 5910                 * @see Option#converter() */
 5911                public ITypeConverter<?>[] converters() { return converters; }
 5912
 5913                /** Returns a regular expression to split option parameter values or {@code ""} if the value should not be split.
 5914                 * @see Option#split() */
 5915                public String splitRegex()     { return splitRegex; }
 5916
 5917                /** Returns whether this option should be excluded from the usage message.
 5918                 * @see Option#hidden() */
 5919                public boolean hidden()        { return hidden; }
 5920
 5921                /** Returns the type to convert the option or positional parameter to before {@linkplain #setValue(Object) setting} the value. */
 5922                public Class<?> type()         { return type; }
 5923
 5924                /** Returns the type info for this option or positional parameter.
 5925                 * @return type information that does not require {@code Class} objects and be constructed both at runtime and compile time
 5926                 * @since 4.0
 5927                 */
 5928                public ITypeInfo typeInfo()    { return typeInfo; }
 5929
 5930                /** Returns the user object associated with this option or positional parameters.
 5931                 * @return may return the annotated program element, or some other useful object
 5932                 * @since 4.0 */
 5933                public Object userObject()     { return userObject; }
 5934
 5935                /** Returns the default value of this option or positional parameter, before splitting and type conversion.
 5936                 * A value of {@code null} means this option or positional parameter does not have a default. */
 5937                public String defaultValue()   { return defaultValue; }
 5938                /** Returns the initial value this option or positional parameter. If {@link #hasInitialValue()} is true,
 5939                 * the option will be reset to the initial value before parsing (regardless of whether a default value exists),
 5940                 * to clear values that would otherwise remain from parsing previous input. */
 5941                public Object initialValue()     { return initialValue; }
 5942                /** Determines whether the option or positional parameter will be reset to the {@link #initialValue()}
 5943                 * before parsing new input.*/
 5944                public boolean hasInitialValue() { return hasInitialValue; }
 5945
 5946                /** Returns whether this option or positional parameter's default value should be shown in the usage help. */
 5947                public Help.Visibility showDefaultValue() { return showDefaultValue; }
 5948
 5949                /** Returns the completion candidates for this option or positional parameter, or {@code null}.
 5950                 * @since 3.2 */
 5951                public Iterable<String> completionCandidates() { return completionCandidates; }
 5952
 5953                /** Returns the {@link IGetter} that is responsible for supplying the value of this argument. */
 5954                public IGetter getter()        { return getter; }
 5955                /** Returns the {@link ISetter} that is responsible for modifying the value of this argument. */
 5956                public ISetter setter()        { return setter; }
 5957                /** Returns the {@link IScope} that determines where the setter sets the value (or the getter gets the value) of this argument. */
 5958                public IScope scope()          { return scope; }
 5959
 5960                public String toString() { return toString; }
 5961
 5962                /** Sets whether this is a required option or positional parameter, and returns this builder. */
 5963                public T required(boolean required)          { this.required = required; return self(); }
 5964
 5965                /** Sets whether this option prompts the user to enter a value on the command line, and returns this builder. */
 5966                public T interactive(boolean interactive)    { this.interactive = interactive; return self(); }
 5967
 5968                /** Sets the description of this option, used when generating the usage documentation, and returns this builder.
 5969                 * @see Option#description() */
 5970                public T description(String... description)  { this.description = Assert.notNull(description, "description").clone(); return self(); }
 5971
 5972                /** Sets the description key that is used to look up the description in a resource bundle, and returns this builder.
 5973                 * @see Option#descriptionKey()
 5974                 * @see Parameters#descriptionKey()
 5975                 * @since 3.6 */
 5976                public T descriptionKey(String descriptionKey) { this.descriptionKey = descriptionKey; return self(); }
 5977
 5978                /** Sets how many arguments this option or positional parameter requires, and returns this builder. */
 5979                public T arity(String range)                 { return arity(Range.valueOf(range)); }
 5980    
 5981                /** Sets how many arguments this option or positional parameter requires, and returns this builder. */
 5982                public T arity(Range arity)                  { this.arity = Assert.notNull(arity, "arity"); return self(); }
 5983    
 5984                /** Sets the name of the option or positional parameter used in the usage help message, and returns this builder. */
 5985                public T paramLabel(String paramLabel)       { this.paramLabel = Assert.notNull(paramLabel, "paramLabel"); return self(); }
 5986
 5987                /** Sets whether usage syntax decorations around the {@linkplain #paramLabel() paramLabel} should be suppressed.
 5988                 * The default is {@code false}: by default, the paramLabel is surrounded with {@code '['} and {@code ']'} characters
 5989                 * if the value is optional and followed by ellipses ("...") when multiple values can be specified.
 5990                 * @since 3.6.0 */
 5991                public T hideParamSyntax(boolean hideParamSyntax) { this.hideParamSyntax = hideParamSyntax; return self(); }
 5992    
 5993                /** Sets auxiliary type information, and returns this builder.
 5994                 * @param types  the element type(s) when the {@link #type()} is a generic {@code Collection} or a {@code Map};
 5995                 * or the concrete type when the {@link #type()} is an abstract class. */
 5996                public T auxiliaryTypes(Class<?>... types)   { this.auxiliaryTypes = Assert.notNull(types, "types").clone(); return self(); }
 5997    
 5998                /** Sets option/positional param-specific converter (or converters for Maps), and returns this builder. */
 5999                public T converters(ITypeConverter<?>... cs) { this.converters = Assert.notNull(cs, "type converters").clone(); return self(); }
 6000    
 6001                /** Sets a regular expression to split option parameter values or {@code ""} if the value should not be split, and returns this builder. */
 6002                public T splitRegex(String splitRegex)       { this.splitRegex = Assert.notNull(splitRegex, "splitRegex"); return self(); }
 6003    
 6004                /** Sets whether this option or positional parameter's default value should be shown in the usage help, and returns this builder. */
 6005                public T showDefaultValue(Help.Visibility visibility) { showDefaultValue = Assert.notNull(visibility, "visibility"); return self(); }
 6006
 6007                /** Sets the completion candidates for this option or positional parameter, and returns this builder.
 6008                 * @since 3.2 */
 6009                public T completionCandidates(Iterable<String> completionCandidates) { this.completionCandidates = completionCandidates; return self(); }
 6010
 6011                /** Sets whether this option should be excluded from the usage message, and returns this builder. */
 6012                public T hidden(boolean hidden)              { this.hidden = hidden; return self(); }
 6013    
 6014                /** Sets the type to convert the option or positional parameter to before {@linkplain #setValue(Object) setting} the value, and returns this builder.
 6015                 * @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. */
 6016                public T type(Class<?> propertyType)         { this.type = Assert.notNull(propertyType, "type"); return self(); }
 6017
 6018                /** Sets the type info for this option or positional parameter, and returns this builder.
 6019                 * @param typeInfo type information that does not require {@code Class} objects and be constructed both at runtime and compile time
 6020                 * @since 4.0 */
 6021                public T typeInfo(ITypeInfo typeInfo) {
 6022                    setTypeInfo(Assert.notNull(typeInfo, "typeInfo"));
 6023                    return self();
 6024                }
 6025                private void setTypeInfo(ITypeInfo newValue) {
 6026                    this.typeInfo = newValue;
 6027                    if (typeInfo != null) {
 6028                        type = typeInfo.getType();
 6029                        auxiliaryTypes = typeInfo.getAuxiliaryTypes();
 6030                    }
 6031                }
 6032
 6033                /** Sets the user object associated with this option or positional parameters, and returns this builder.
 6034                 * @param userObject may be the annotated program element, or some other useful object
 6035                 * @since 4.0 */
 6036                public T userObject(Object userObject)     { this.userObject = Assert.notNull(userObject, "userObject"); return self(); }
 6037
 6038                /** Sets the default value of this option or positional parameter to the specified value, and returns this builder.
 6039                 * Before parsing the command line, the result of {@linkplain #splitRegex() splitting} and {@linkplain #converters() type converting}
 6040                 * this default value is applied to the option or positional parameter. A value of {@code null} or {@code "__no_default_value__"} means no default. */
 6041                public T defaultValue(String defaultValue)   { this.defaultValue = defaultValue; return self(); }
 6042
 6043                /** Sets the initial value of this option or positional parameter to the specified value, and returns this builder.
 6044                 * If {@link #hasInitialValue()} is true, the option will be reset to the initial value before parsing (regardless
 6045                 * of whether a default value exists), to clear values that would otherwise remain from parsing previous input. */
 6046                public T initialValue(Object initialValue)   { this.initialValue = initialValue; return self(); }
 6047
 6048                /** Determines whether the option or positional parameter will be reset to the {@link #initialValue()}
 6049                 * before parsing new input.*/
 6050                public T hasInitialValue(boolean hasInitialValue)   { this.hasInitialValue = hasInitialValue; return self(); }
 6051
 6052                /** Sets the {@link IGetter} that is responsible for getting the value of this argument, and returns this builder. */
 6053                public T getter(IGetter getter)              { this.getter = getter; return self(); }
 6054                /** Sets the {@link ISetter} that is responsible for modifying the value of this argument, and returns this builder. */
 6055                public T setter(ISetter setter)              { this.setter = setter; return self(); }
 6056                /** Sets the {@link IScope} that targets where the setter sets the value, and returns this builder. */
 6057                public T scope(IScope scope)                 { this.scope = scope; return self(); }
 6058
 6059                /** Sets the string respresentation of this option or positional parameter to the specified value, and returns this builder. */
 6060                public T withToString(String toString)       { this.toString = toString; return self(); }
 6061            }
 6062        }
 6063        /** The {@code OptionSpec} class models aspects of a <em>named option</em> of a {@linkplain CommandSpec command}, including whether
 6064         * it is required or optional, the option parameters supported (or required) by the option,
 6065         * and attributes for the usage help message describing the option.
 6066         * <p>
 6067         * 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.
 6068         * Depending on the option's {@link #arity() arity},
 6069         * the parser may expect it to have option parameters. The parser will call {@link #setValue(Object) setValue} on
 6070         * the matched option for each of the option parameters encountered.
 6071         * </p><p>
 6072         * For multi-value options, the {@code type} may be an array, a {@code Collection} or a {@code Map}. In this case
 6073         * the parser will get the data structure by calling {@link #getValue() getValue} and modify the contents of this data structure.
 6074         * (In the case of arrays, the array is replaced with a new instance with additional elements.)
 6075         * </p><p>
 6076         * Before calling the setter, picocli converts the option parameter value from a String to the option parameter's type.
 6077         * </p>
 6078         * <ul>
 6079         *   <li>If a option-specific {@link #converters() converter} is configured, this will be used for type conversion.
 6080         *   If the option's type is a {@code Map}, the map may have different types for its keys and its values, so
 6081         *   {@link #converters() converters} should provide two converters: one for the map keys and one for the map values.</li>
 6082         *   <li>Otherwise, the option's {@link #type() type} is used to look up a converter in the list of
 6083         *   {@linkplain CommandLine#registerConverter(Class, ITypeConverter) registered converters}.
 6084         *   For multi-value options,
 6085         *   the {@code type} may be an array, or a {@code Collection} or a {@code Map}. In that case the elements are converted
 6086         *   based on the option's {@link #auxiliaryTypes() auxiliaryTypes}. The auxiliaryType is used to look up
 6087         *   the converter(s) to use to convert the individual parameter values.
 6088         *   Maps may have different types for its keys and its values, so {@link #auxiliaryTypes() auxiliaryTypes}
 6089         *   should provide two types: one for the map keys and one for the map values.</li>
 6090         * </ul>
 6091         * <p>
 6092         * {@code OptionSpec} objects are used by the picocli command line interpreter and help message generator.
 6093         * Picocli can construct an {@code OptionSpec} automatically from fields and methods with {@link Option @Option}
 6094         * annotations. Alternatively an {@code OptionSpec} can be constructed programmatically.
 6095         * </p><p>
 6096         * When an {@code OptionSpec} is created from an {@link Option @Option} -annotated field or method, it is "bound"
 6097         * to that field or method: this field is set (or the method is invoked) when the option is matched and
 6098         * {@link #setValue(Object) setValue} is called.
 6099         * Programmatically constructed {@code OptionSpec} instances will remember the value passed to the
 6100         * {@link #setValue(Object) setValue} method so it can be retrieved with the {@link #getValue() getValue} method.
 6101         * This behaviour can be customized by installing a custom {@link IGetter} and {@link ISetter} on the {@code OptionSpec}.
 6102         * </p>
 6103         * @since 3.0 */
 6104        public static class OptionSpec extends ArgSpec implements IOrdered {
 6105            static final int DEFAULT_ORDER = -1;
 6106            private String[] names;
 6107            private boolean help;
 6108            private boolean usageHelp;
 6109            private boolean versionHelp;
 6110            private int order;
 6111
 6112            public static OptionSpec.Builder builder(String name, String... names) {
 6113                String[] copy = new String[Assert.notNull(names, "names").length + 1];
 6114                copy[0] = Assert.notNull(name, "name");
 6115                System.arraycopy(names, 0, copy, 1, names.length);
 6116                return new Builder(copy);
 6117            }
 6118            public static OptionSpec.Builder builder(String[] names) { return new Builder(names); }
 6119            public static OptionSpec.Builder builder(IAnnotatedElement source, IFactory factory) { return new Builder(source, factory); }
 6120
 6121            /** Ensures all attributes of this {@code OptionSpec} have a valid value; throws an {@link InitializationException} if this cannot be achieved. */
 6122            private OptionSpec(Builder builder) {
 6123                super(builder);
 6124                if (builder.names == null) {
 6125                    throw new InitializationException("OptionSpec names cannot be null. Specify at least one option name.");
 6126                }
 6127                names = builder.names.clone();
 6128                help = builder.help;
 6129                usageHelp = builder.usageHelp;
 6130                versionHelp = builder.versionHelp;
 6131                order = builder.order;
 6132
 6133                if (names.length == 0 || Arrays.asList(names).contains("")) {
 6134                    throw new InitializationException("Invalid names: " + Arrays.toString(names));
 6135                }
 6136                if (toString() == null) { toString = "option " + longestName(); }
 6137
 6138//                if (arity().max == 0 && !(isBoolean(type()) || (isMultiValue() && isBoolean(auxiliaryTypes()[0])))) {
 6139//                    throw new InitializationException("Option " + longestName() + " is not a boolean so should not be defined with arity=" + arity());
 6140//                }
 6141            }
 6142    
 6143            /** Returns a new Builder initialized with the attributes from this {@code OptionSpec}. Calling {@code build} immediately will return a copy of this {@code OptionSpec}.
 6144             * @return a builder that can create a copy of this spec
 6145             */
 6146            public Builder toBuilder()    { return new Builder(this); }
 6147            @Override public boolean isOption()     { return true; }
 6148            @Override public boolean isPositional() { return false; }
 6149
 6150            protected boolean internalShowDefaultValue(boolean usageMessageShowDefaults) {
 6151                return super.internalShowDefaultValue(usageMessageShowDefaults) && !help() && !versionHelp() && !usageHelp();
 6152            }
 6153
 6154            /** Returns the description template of this option, before variables are {@linkplain Option#description() rendered}.
 6155             * If a resource bundle has been {@linkplain ArgSpec#messages(Messages) set}, this method will first try to find a value in the resource bundle:
 6156             * If the resource bundle has no entry for the {@code fully qualified commandName + "." + descriptionKey} or for the unqualified {@code descriptionKey},
 6157             * an attempt is made to find the option description using any of the option names (without leading hyphens) as key,
 6158             * first with the {@code fully qualified commandName + "."} prefix, then without.
 6159             * @see CommandSpec#qualifiedName(String)
 6160             * @see Option#description() */
 6161            @Override public String[] description() {
 6162                if (messages() == null) { return super.description(); }
 6163                String[] newValue = messages().getStringArray(descriptionKey(), null);
 6164                if (newValue != null) { return newValue; }
 6165                for (String name : names()) {
 6166                    newValue = messages().getStringArray(CommandSpec.stripPrefix(name), null);
 6167                    if (newValue != null) { return newValue; }
 6168                }
 6169                return super.description();
 6170            }
 6171
 6172            /** Returns one or more option names. The returned array will contain at least one option name.
 6173             * @see Option#names() */
 6174            public String[] names() { return names.clone(); }
 6175
 6176            /** Returns the longest {@linkplain #names() option name}. */
 6177            public String longestName() { return Help.ShortestFirst.longestFirst(names.clone())[0]; }
 6178
 6179            /** Returns the shortest {@linkplain #names() option name}.
 6180             * @since 3.8 */
 6181            public String shortestName() { return Help.ShortestFirst.sort(names.clone())[0]; }
 6182
 6183            /** Returns the position in the options list in the usage help message at which this option should be shown.
 6184             * Options with a lower number are shown before options with a higher number.
 6185             * This attribute is only honored if {@link UsageMessageSpec#sortOptions()} is {@code false} for this command.
 6186             * @see Option#order()
 6187             * @since 3.9 */
 6188            public int order() { return this.order; }
 6189
 6190            /** Returns whether this option disables validation of the other arguments.
 6191             * @see Option#help()
 6192             * @deprecated Use {@link #usageHelp()} and {@link #versionHelp()} instead. */
 6193            @Deprecated public boolean help() { return help; }
 6194    
 6195            /** Returns whether this option allows the user to request usage help.
 6196             * @see Option#usageHelp()  */
 6197            public boolean usageHelp()    { return usageHelp; }
 6198    
 6199            /** Returns whether this option allows the user to request version information.
 6200             * @see Option#versionHelp()  */
 6201            public boolean versionHelp()  { return versionHelp; }
 6202            public boolean equals(Object obj) {
 6203                if (obj == this) { return true; }
 6204                if (!(obj instanceof OptionSpec)) { return false; }
 6205                OptionSpec other = (OptionSpec) obj;
 6206                boolean result = super.equalsImpl(other)
 6207                        && help == other.help
 6208                        && usageHelp == other.usageHelp
 6209                        && versionHelp == other.versionHelp
 6210                        && order == other.order
 6211                        && new HashSet<String>(Arrays.asList(names)).equals(new HashSet<String>(Arrays.asList(other.names)));
 6212                return result;
 6213            }
 6214            public int hashCode() {
 6215                return super.hashCodeImpl()
 6216                        + 37 * Assert.hashCode(help)
 6217                        + 37 * Assert.hashCode(usageHelp)
 6218                        + 37 * Assert.hashCode(versionHelp)
 6219                        + 37 * Arrays.hashCode(names)
 6220                        + 37 * order;
 6221            }
 6222    
 6223            /** Builder responsible for creating valid {@code OptionSpec} objects.
 6224             * @since 3.0
 6225             */
 6226            public static class Builder extends ArgSpec.Builder<Builder> {
 6227                private String[] names;
 6228                private boolean help;
 6229                private boolean usageHelp;
 6230                private boolean versionHelp;
 6231                private int order = DEFAULT_ORDER;
 6232
 6233                private Builder(String[] names) { this.names = names; }
 6234                private Builder(OptionSpec original) {
 6235                    super(original);
 6236                    names = original.names;
 6237                    help = original.help;
 6238                    usageHelp = original.usageHelp;
 6239                    versionHelp = original.versionHelp;
 6240                    order = original.order;
 6241                }
 6242                private Builder(IAnnotatedElement member, IFactory factory) {
 6243                    super(member.getAnnotation(Option.class), member, factory);
 6244                    Option option = member.getAnnotation(Option.class);
 6245                    names = option.names();
 6246                    help = option.help();
 6247                    usageHelp = option.usageHelp();
 6248                    versionHelp = option.versionHelp();
 6249                    order = option.order();
 6250                }
 6251
 6252                /** Returns a valid {@code OptionSpec} instance. */
 6253                @Override public OptionSpec build() { return new OptionSpec(this); }
 6254                /** Returns this builder. */
 6255                @Override protected Builder self() { return this; }
 6256
 6257                /** Returns one or more option names. At least one option name is required.
 6258                 * @see Option#names() */
 6259                public String[] names()       { return names; }
 6260
 6261                /** Returns whether this option disables validation of the other arguments.
 6262                 * @see Option#help()
 6263                 * @deprecated Use {@link #usageHelp()} and {@link #versionHelp()} instead. */
 6264                @Deprecated public boolean help() { return help; }
 6265
 6266                /** Returns whether this option allows the user to request usage help.
 6267                 * @see Option#usageHelp()  */
 6268                public boolean usageHelp()    { return usageHelp; }
 6269
 6270                /** Returns whether this option allows the user to request version information.
 6271                 * @see Option#versionHelp()  */
 6272                public boolean versionHelp()  { return versionHelp; }
 6273
 6274                /** Returns the position in the options list in the usage help message at which this option should be shown.
 6275                 * Options with a lower number are shown before options with a higher number.
 6276                 * This attribute is only honored if {@link UsageMessageSpec#sortOptions()} is {@code false} for this command.
 6277                 * @see Option#order()
 6278                 * @since 3.9 */
 6279                public int order()  { return order; }
 6280
 6281                /** Replaces the option names with the specified values. At least one option name is required, and returns this builder.
 6282                 * @return this builder instance to provide a fluent interface */
 6283                public Builder names(String... names)           { this.names = Assert.notNull(names, "names").clone(); return self(); }
 6284    
 6285                /** Sets whether this option disables validation of the other arguments, and returns this builder. */
 6286                public Builder help(boolean help)               { this.help = help; return self(); }
 6287    
 6288                /** Sets whether this option allows the user to request usage help, and returns this builder. */
 6289                public Builder usageHelp(boolean usageHelp)     { this.usageHelp = usageHelp; return self(); }
 6290    
 6291                /** Sets whether this option allows the user to request version information, and returns this builder.*/
 6292                public Builder versionHelp(boolean versionHelp) { this.versionHelp = versionHelp; return self(); }
 6293
 6294                /** Sets the position in the options list in the usage help message at which this option should be shown, and returns this builder.
 6295                 * @since 3.9 */
 6296                public Builder order(int order) { this.order = order; return self(); }
 6297            }
 6298        }
 6299        /** The {@code PositionalParamSpec} class models aspects of a <em>positional parameter</em> of a {@linkplain CommandSpec command}, including whether
 6300         * it is required or optional, and attributes for the usage help message describing the positional parameter.
 6301         * <p>
 6302         * Positional parameters have an {@link #index() index} (or a range of indices). A positional parameter is matched when the parser
 6303         * encounters a command line argument at that index. Named options and their parameters do not change the index counter,
 6304         * so the command line can contain a mixture of positional parameters and named options.
 6305         * </p><p>
 6306         * Depending on the positional parameter's {@link #arity() arity}, the parser may consume multiple command line
 6307         * arguments starting from the current index. The parser will call {@link #setValue(Object) setValue} on
 6308         * the {@code PositionalParamSpec} for each of the parameters encountered.
 6309         * For multi-value positional parameters, the {@code type} may be an array, a {@code Collection} or a {@code Map}. In this case
 6310         * the parser will get the data structure by calling {@link #getValue() getValue} and modify the contents of this data structure.
 6311         * (In the case of arrays, the array is replaced with a new instance with additional elements.)
 6312         * </p><p>
 6313         * Before calling the setter, picocli converts the positional parameter value from a String to the parameter's type.
 6314         * </p>
 6315         * <ul>
 6316         *   <li>If a positional parameter-specific {@link #converters() converter} is configured, this will be used for type conversion.
 6317         *   If the positional parameter's type is a {@code Map}, the map may have different types for its keys and its values, so
 6318         *   {@link #converters() converters} should provide two converters: one for the map keys and one for the map values.</li>
 6319         *   <li>Otherwise, the positional parameter's {@link #type() type} is used to look up a converter in the list of
 6320         *   {@linkplain CommandLine#registerConverter(Class, ITypeConverter) registered converters}. For multi-value positional parameters,
 6321         *   the {@code type} may be an array, or a {@code Collection} or a {@code Map}. In that case the elements are converted
 6322         *   based on the positional parameter's {@link #auxiliaryTypes() auxiliaryTypes}. The auxiliaryType is used to look up
 6323         *   the converter(s) to use to convert the individual parameter values.
 6324         *   Maps may have different types for its keys and its values, so {@link #auxiliaryTypes() auxiliaryTypes}
 6325         *   should provide two types: one for the map keys and one for the map values.</li>
 6326         * </ul>
 6327         * <p>
 6328         * {@code PositionalParamSpec} objects are used by the picocli command line interpreter and help message generator.
 6329         * Picocli can construct a {@code PositionalParamSpec} automatically from fields and methods with {@link Parameters @Parameters}
 6330         * annotations. Alternatively a {@code PositionalParamSpec} can be constructed programmatically.
 6331         * </p><p>
 6332         * When a {@code PositionalParamSpec} is created from a {@link Parameters @Parameters} -annotated field or method,
 6333         * it is "bound" to that field or method: this field is set (or the method is invoked) when the position is matched
 6334         * and {@link #setValue(Object) setValue} is called.
 6335         * Programmatically constructed {@code PositionalParamSpec} instances will remember the value passed to the
 6336         * {@link #setValue(Object) setValue} method so it can be retrieved with the {@link #getValue() getValue} method.
 6337         * This behaviour can be customized by installing a custom {@link IGetter} and {@link ISetter} on the {@code PositionalParamSpec}.
 6338         * </p>
 6339         * @since 3.0 */
 6340        public static class PositionalParamSpec extends ArgSpec {
 6341            private Range index;
 6342            private Range capacity;
 6343
 6344            /** Ensures all attributes of this {@code PositionalParamSpec} have a valid value; throws an {@link InitializationException} if this cannot be achieved. */
 6345            private PositionalParamSpec(Builder builder) {
 6346                super(builder);
 6347                index = builder.index == null ? Range.valueOf("*") : builder.index; 
 6348                capacity = builder.capacity == null ? Range.parameterCapacity(arity(), index) : builder.capacity;
 6349                if (toString == null) { toString = "positional parameter[" + index() + "]"; }
 6350            }
 6351            public static Builder builder() { return new Builder(); }
 6352            public static Builder builder(IAnnotatedElement source, IFactory factory) { return new Builder(source, factory); }
 6353            /** Returns a new Builder initialized with the attributes from this {@code PositionalParamSpec}. Calling {@code build} immediately will return a copy of this {@code PositionalParamSpec}.
 6354             * @return a builder that can create a copy of this spec
 6355             */
 6356            public Builder toBuilder()    { return new Builder(this); }
 6357            @Override public boolean isOption()     { return false; }
 6358            @Override public boolean isPositional() { return true; }
 6359
 6360            /** Returns the description template of this positional parameter, before variables are {@linkplain Parameters#description() rendered}.
 6361             * If a resource bundle has been {@linkplain ArgSpec#messages(Messages) set}, this method will first try to find a value in the resource bundle:
 6362             * If the resource bundle has no entry for the {@code fully qualified commandName + "." + descriptionKey} or for the unqualified {@code descriptionKey},
 6363             * an attempt is made to find the positional parameter description using {@code paramLabel() + "[" + index() + "]"} as key,
 6364             * first with the {@code fully qualified commandName + "."} prefix, then without.
 6365             * @see Parameters#description()
 6366             * @see CommandSpec#qualifiedName(String)
 6367             * @since 3.6 */
 6368            @Override public String[] description() {
 6369                if (messages() == null) { return super.description(); }
 6370                String[] newValue = messages().getStringArray(descriptionKey(), null);
 6371                if (newValue != null) { return newValue; }
 6372                newValue = messages().getStringArray(paramLabel() + "[" + index() + "]", null);
 6373                if (newValue != null) { return newValue; }
 6374                return super.description();
 6375            }
 6376
 6377            /** Returns an index or range specifying which of the command line arguments should be assigned to this positional parameter.
 6378             * @see Parameters#index() */
 6379            public Range index()            { return index; }
 6380            private Range capacity()        { return capacity; }
 6381
 6382            public int hashCode() {
 6383                return super.hashCodeImpl()
 6384                        + 37 * Assert.hashCode(capacity)
 6385                        + 37 * Assert.hashCode(index);
 6386            }
 6387            public boolean equals(Object obj) {
 6388                if (obj == this) {
 6389                    return true;
 6390                }
 6391                if (!(obj instanceof PositionalParamSpec)) {
 6392                    return false;
 6393                }
 6394                PositionalParamSpec other = (PositionalParamSpec) obj;
 6395                return super.equalsImpl(other)
 6396                        && Assert.equals(this.capacity, other.capacity)
 6397                        && Assert.equals(this.index, other.index);
 6398            }
 6399    
 6400            /** Builder responsible for creating valid {@code PositionalParamSpec} objects.
 6401             * @since 3.0
 6402             */
 6403            public static class Builder extends ArgSpec.Builder<Builder> {
 6404                private Range capacity;
 6405                private Range index;
 6406                private Builder() {}
 6407                private Builder(PositionalParamSpec original) {
 6408                    super(original);
 6409                    index = original.index;
 6410                    capacity = original.capacity;
 6411                }
 6412                private Builder(IAnnotatedElement member, IFactory factory) {
 6413                    super(member.getAnnotation(Parameters.class), member, factory);
 6414                    index = Range.parameterIndex(member);
 6415                    capacity = Range.parameterCapacity(member);
 6416                }
 6417                /** Returns a valid {@code PositionalParamSpec} instance. */
 6418                @Override public PositionalParamSpec build() { return new PositionalParamSpec(this); }
 6419                /** Returns this builder. */
 6420                @Override protected Builder self()  { return this; }
 6421
 6422                /** Returns an index or range specifying which of the command line arguments should be assigned to this positional parameter.
 6423                 * @see Parameters#index() */
 6424                public Range index()            { return index; }
 6425
 6426                /** Sets the index or range specifying which of the command line arguments should be assigned to this positional parameter, and returns this builder. */
 6427                public Builder index(String range)  { return index(Range.valueOf(range)); }
 6428    
 6429                /** Sets the index or range specifying which of the command line arguments should be assigned to this positional parameter, and returns this builder. */
 6430                public Builder index(Range index)   { this.index = index; return self(); }
 6431
 6432                Range capacity()                   { return capacity; }
 6433                Builder capacity(Range capacity)   { this.capacity = capacity; return self(); }
 6434            }
 6435        }
 6436
 6437        /** Interface for sorting {@link OptionSpec options} and {@link ArgGroupSpec groups} together.
 6438         * @since 4.0 */
 6439        public interface IOrdered {
 6440            /** Returns the position in the options list in the usage help message at which this element should be shown.
 6441             * Elements with a lower number are shown before elements with a higher number.
 6442             * This attribute is only honored if {@link UsageMessageSpec#sortOptions()} is {@code false} for this command. */
 6443            int order();
 6444        }
 6445
 6446        /** The {@code ArgGroupSpec} class models a {@link ArgGroup group} of arguments (options, positional parameters or a mixture of the two).
 6447         * @see ArgGroup
 6448         * @since 4.0 */
 6449        public static class ArgGroupSpec implements IOrdered {
 6450            static final int DEFAULT_ORDER = -1;
 6451            private static final String NO_HEADING = "__no_heading__";
 6452            private static final String NO_HEADING_KEY = "__no_heading_key__";
 6453            private final String heading;
 6454            private final String headingKey;
 6455            private final boolean exclusive;
 6456            private final Range multiplicity;
 6457            private final boolean validate;
 6458            private final int order;
 6459            private final IGetter getter;
 6460            private final ISetter setter;
 6461            private final IScope scope;
 6462            private final ITypeInfo typeInfo;
 6463            private final List<ArgGroupSpec> subgroups;
 6464            private final Set<ArgSpec> args;
 6465            private Messages messages;
 6466            private ArgGroupSpec parentGroup;
 6467            private String id = "1";
 6468
 6469            ArgGroupSpec(ArgGroupSpec.Builder builder) {
 6470                heading          = NO_HEADING    .equals(builder.heading)    ? null : builder.heading;
 6471                headingKey       = NO_HEADING_KEY.equals(builder.headingKey) ? null : builder.headingKey;
 6472                exclusive        = builder.exclusive;
 6473                multiplicity     = builder.multiplicity;
 6474                validate         = builder.validate;
 6475                order            = builder.order;
 6476                typeInfo         = builder.typeInfo;
 6477                getter           = builder.getter;
 6478                setter           = builder.setter;
 6479                scope            = builder.scope;
 6480
 6481                args      = Collections.unmodifiableSet(new LinkedHashSet<ArgSpec>(builder.args()));
 6482                subgroups = Collections.unmodifiableList(new ArrayList<ArgGroupSpec>(builder.subgroups()));
 6483                if (args.isEmpty() && subgroups.isEmpty()) { throw new InitializationException("ArgGroup has no options or positional parameters, and no subgroups"); }
 6484
 6485                int i = 1;
 6486                for (ArgGroupSpec sub : subgroups) { sub.parentGroup = this; sub.id = id + "." + i++; }
 6487                for (ArgSpec arg : args)           { arg.group = this; }
 6488            }
 6489
 6490            /** Returns a new {@link Builder}.
 6491             * @return a new ArgGroupSpec.Builder instance */
 6492            public static Builder builder() { return new Builder(); }
 6493
 6494            /** Returns a new {@link Builder} associated with the specified annotated element.
 6495             * @param annotatedElement the annotated element containing {@code @Option} and {@code @Parameters}
 6496             * @return a new ArgGroupSpec.Builder instance */
 6497            public static Builder builder(IAnnotatedElement annotatedElement) { return new Builder(Assert.notNull(annotatedElement, "annotatedElement")); }
 6498
 6499            /** Returns whether this is a mutually exclusive group; {@code true} by default.
 6500             * If {@code false}, this is a co-occurring group. Ignored if {@link #validate()} is {@code false}.
 6501             * @see ArgGroup#exclusive() */
 6502            public boolean exclusive() { return exclusive; }
 6503
 6504            /** Returns the multiplicity of this group: how many occurrences it may have on the command line; {@code "0..1"} (optional) by default.
 6505             * A group can be made required by specifying a multiplicity of {@code "1"}. For a group of mutually exclusive arguments,
 6506             * being required means that one of the arguments in the group must appear on the command line, or a MissingParameterException is thrown.
 6507             * For a group of co-occurring arguments, being required means that all arguments in the group must appear on the command line.
 6508             * Ignored if {@link #validate()} is {@code false}.
 6509             * @see ArgGroup#multiplicity() */
 6510            public Range multiplicity() { return multiplicity; }
 6511
 6512            /** Returns whether picocli should validate the rules of this group:
 6513             * for a mutually exclusive group this means that no more than one arguments in the group is specified on the command line;
 6514             * for a co-ocurring group this means that all arguments in the group are specified on the command line.
 6515             * {@code true} by default.
 6516             * @see ArgGroup#validate() */
 6517            public boolean validate() { return validate; }
 6518
 6519            /** Returns the position in the options list in the usage help message at which this group should be shown.
 6520             * Options with a lower number are shown before options with a higher number.
 6521             * This attribute is only honored if {@link UsageMessageSpec#sortOptions()} is {@code false} for this command. */
 6522            public int order() { return this.order; }
 6523
 6524            /** Returns the heading of this group (may be {@code null}), used when generating the usage documentation.
 6525             * @see ArgGroup#heading() */
 6526            public String heading()  {
 6527                if (messages() == null) { return heading; }
 6528                String newValue = messages().getString(headingKey(), null);
 6529                if (newValue != null) { return newValue; }
 6530                return heading;
 6531            }
 6532
 6533            /** Returns the heading key of this group (may be {@code null}), used to get the heading from a resource bundle.
 6534             * @see ArgGroup#headingKey()  */
 6535            public String headingKey() { return headingKey; }
 6536
 6537            /**
 6538             * Returns the parent group that this group is part of, or {@code null} if this group is not part of a composite.
 6539             */
 6540            public ArgGroupSpec parentGroup() { return parentGroup; }
 6541
 6542            /** Return the subgroups that this group is composed of; may be empty but not {@code null}.
 6543             * @return immutable list of subgroups that this group is composed of. */
 6544            public List<ArgGroupSpec> subgroups() { return subgroups; }
 6545
 6546            /**
 6547             * Returns {@code true} if this group is a subgroup (or a nested sub-subgroup, to any level of depth)
 6548             * of the specified group, {@code false} otherwise.
 6549             * @param group the group to check if it contains this group
 6550             * @return {@code true} if this group is a subgroup or a nested sub-subgroup of the specified group
 6551             */
 6552            public boolean isSubgroupOf(ArgGroupSpec group) {
 6553                for (ArgGroupSpec sub : group.subgroups) {
 6554                    if (this == sub) { return true; }
 6555                    if (isSubgroupOf(sub)) { return true; }
 6556                }
 6557                return false;
 6558            }
 6559            /** Returns the type info for the annotated program element associated with this group.
 6560             * @return type information that does not require {@code Class} objects and be constructed both at runtime and compile time
 6561             */
 6562            public ITypeInfo typeInfo()    { return typeInfo; }
 6563
 6564            /** Returns the {@link IGetter} that is responsible for supplying the value of the annotated program element associated with this group. */
 6565            public IGetter getter()        { return getter; }
 6566            /** Returns the {@link ISetter} that is responsible for modifying the value of the annotated program element associated with this group. */
 6567            public ISetter setter()        { return setter; }
 6568            /** 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. */
 6569            public IScope scope()          { return scope; }
 6570
 6571            Object userObject() { try { return getter.get(); } catch (Exception ex) { return ex.toString(); } }
 6572            String id() { return id; }
 6573
 6574            /** Returns the options and positional parameters in this group; may be empty but not {@code null}. */
 6575            public Set<ArgSpec> args() { return args; }
 6576            /** Returns the required options and positional parameters in this group; may be empty but not {@code null}. */
 6577            public Set<ArgSpec> requiredArgs() {
 6578                Set<ArgSpec> result = new LinkedHashSet<ArgSpec>(args);
 6579                for (Iterator<ArgSpec> iter = result.iterator(); iter.hasNext(); ) {
 6580                    if (!iter.next().required()) { iter.remove(); }
 6581                }
 6582                return Collections.unmodifiableSet(result);
 6583            }
 6584
 6585            /** Returns the list of positional parameters configured for this group.
 6586             * @return an immutable list of positional parameters in this group. */
 6587            public List<PositionalParamSpec> positionalParameters() {
 6588                List<PositionalParamSpec> result = new ArrayList<PositionalParamSpec>();
 6589                for (ArgSpec arg : args()) { if (arg instanceof PositionalParamSpec) { result.add((PositionalParamSpec) arg); } }
 6590                return Collections.unmodifiableList(result);
 6591            }
 6592            /** Returns the list of options configured for this group.
 6593             * @return an immutable list of options in this group. */
 6594            public List<OptionSpec> options() {
 6595                List<OptionSpec> result = new ArrayList<OptionSpec>();
 6596                for (ArgSpec arg : args()) { if (arg instanceof OptionSpec) { result.add((OptionSpec) arg); } }
 6597                return Collections.unmodifiableList(result);
 6598            }
 6599
 6600            public String synopsis() {
 6601                return synopsisText(new Help.ColorScheme(Help.Ansi.OFF)).toString();
 6602            }
 6603
 6604            public Text synopsisText(Help.ColorScheme colorScheme) {
 6605                String infix = exclusive() ? " | " : " ";
 6606                Text synopsis = colorScheme.ansi().new Text(0);
 6607                for (ArgSpec arg : args()) {
 6608                    if (synopsis.length > 0) { synopsis = synopsis.concat(infix); }
 6609                    if (arg instanceof OptionSpec) {
 6610                        synopsis = concatOptionText(synopsis, colorScheme, (OptionSpec) arg);
 6611                    } else {
 6612                        synopsis = concatPositionalText(synopsis, colorScheme, (PositionalParamSpec) arg);
 6613                    }
 6614                }
 6615                for (ArgGroupSpec subgroup : subgroups()) {
 6616                    if (synopsis.length > 0) { synopsis = synopsis.concat(infix); }
 6617                    synopsis = synopsis.concat(subgroup.synopsisText(colorScheme));
 6618                }
 6619                String prefix = multiplicity().min > 0 ? "(" : "[";
 6620                String postfix = multiplicity().min > 0 ? ")" : "]";
 6621                Text result = colorScheme.ansi().text(prefix).concat(synopsis).concat(postfix);
 6622                int i = 1;
 6623                for (; i < multiplicity.min; i++) {
 6624                    result = result.concat(" (").concat(synopsis).concat(")");
 6625                }
 6626                if (multiplicity().isVariable) {
 6627                    result = result.concat("...");
 6628                } else {
 6629                    for (; i < multiplicity.max; i++) {
 6630                        result = result.concat(" [").concat(synopsis).concat("]");
 6631                    }
 6632                }
 6633                return result;
 6634            }
 6635
 6636            private Text concatOptionText(Text text, Help.ColorScheme colorScheme, OptionSpec option) {
 6637                if (!option.hidden()) {
 6638                    Text name = colorScheme.optionText(option.shortestName());
 6639                    Text param = createLabelRenderer(option.commandSpec).renderParameterLabel(option, colorScheme.ansi(), colorScheme.optionParamStyles);
 6640                    text = text.concat(open(option)).concat(name).concat(param).concat(close(option));
 6641                    if (option.isMultiValue()) { // e.g., -x=VAL [-x=VAL]...
 6642                        text = text.concat(" [").concat(name).concat(param).concat("]...");
 6643                    }
 6644                }
 6645                return text;
 6646            }
 6647
 6648            private Text concatPositionalText(Text text, Help.ColorScheme colorScheme, PositionalParamSpec positionalParam) {
 6649                if (!positionalParam.hidden()) {
 6650                    Text label = createLabelRenderer(positionalParam.commandSpec).renderParameterLabel(positionalParam, colorScheme.ansi(), colorScheme.parameterStyles);
 6651                    text = text.concat(open(positionalParam)).concat(label).concat(close(positionalParam));
 6652                }
 6653                return text;
 6654            }
 6655            private String open(ArgSpec argSpec)  { return argSpec.required() ? "" : "["; }
 6656            private String close(ArgSpec argSpec) { return argSpec.required() ? "" : "]"; }
 6657
 6658            public Help.IParamLabelRenderer createLabelRenderer(CommandSpec commandSpec) {
 6659                return new Help.DefaultParamLabelRenderer(commandSpec == null ? CommandSpec.create() : commandSpec);
 6660            }
 6661            /** Returns the Messages for this argument group specification, or {@code null}. */
 6662            public Messages messages() { return messages; }
 6663            /** Sets the Messages for this ArgGroupSpec, and returns this ArgGroupSpec.
 6664             * @param msgs the new Messages value, may be {@code null}
 6665             * @see Command#resourceBundle()
 6666             * @see #headingKey()
 6667             */
 6668            public ArgGroupSpec messages(Messages msgs) {
 6669                messages = msgs;
 6670                for (ArgGroupSpec sub : subgroups()) { sub.messages(msgs); }
 6671                return this;
 6672            }
 6673
 6674            @Override public boolean equals(Object obj) {
 6675                if (obj == this) { return true; }
 6676                if (!(obj instanceof ArgGroupSpec)) { return false; }
 6677                ArgGroupSpec other = (ArgGroupSpec) obj;
 6678                return exclusive == other.exclusive
 6679                        && Assert.equals(multiplicity, other.multiplicity)
 6680                        && validate == other.validate
 6681                        && order == other.order
 6682                        && Assert.equals(heading, other.heading)
 6683                        && Assert.equals(headingKey, other.headingKey)
 6684                        && Assert.equals(subgroups, other.subgroups)
 6685                        && Assert.equals(args, other.args);
 6686            }
 6687
 6688            @Override public int hashCode() {
 6689                int result = 17;
 6690                result += 37 * result + Assert.hashCode(exclusive);
 6691                result += 37 * result + Assert.hashCode(multiplicity);
 6692                result += 37 * result + Assert.hashCode(validate);
 6693                result += 37 * result + order;
 6694                result += 37 * result + Assert.hashCode(heading);
 6695                result += 37 * result + Assert.hashCode(headingKey);
 6696                result += 37 * result + Assert.hashCode(subgroups);
 6697                result += 37 * result + Assert.hashCode(args);
 6698                return result;
 6699            }
 6700
 6701            @Override public String toString() {
 6702                List<String> argNames = new ArrayList<String>();
 6703                for (ArgSpec arg : args()) {
 6704                    if (arg instanceof OptionSpec) {
 6705                        argNames.add(((OptionSpec) arg).shortestName());
 6706                    } else {
 6707                        PositionalParamSpec p = (PositionalParamSpec) arg;
 6708                        argNames.add(p.index() + " (" + p.paramLabel() + ")");
 6709                    }
 6710                }
 6711                return "ArgGroup[exclusive=" + exclusive + ", multiplicity=" + multiplicity +
 6712                        ", validate=" + validate + ", order=" + order + ", args=[" + ArgSpec.describe(args()) +
 6713                        "], headingKey=" + quote(headingKey) + ", heading=" + quote(heading) +
 6714                        ", subgroups=" + subgroups + "]";
 6715            }
 6716            private static String quote(String s) { return s == null ? "null" : "'" + s + "'"; }
 6717
 6718            void initUserObject(CommandLine commandLine) {
 6719                if (commandLine == null) { new Tracer().debug("Could not create user object for %s with null CommandLine%n.", this); }
 6720                try {
 6721                    tryInitUserObject(commandLine);
 6722                } catch (PicocliException ex) {
 6723                    throw ex;
 6724                } catch (Exception ex) {
 6725                    throw new InitializationException("Could not create user object for " + this, ex);
 6726                }
 6727            }
 6728            void tryInitUserObject(CommandLine commandLine) throws Exception {
 6729                Tracer tracer = commandLine.tracer;
 6730                if (typeInfo() != null) {
 6731                    tracer.debug("Creating new user object of type %s for group %s%n", typeInfo().getAuxiliaryTypes()[0], synopsis());
 6732                    Object userObject = DefaultFactory.create(commandLine.factory, typeInfo().getAuxiliaryTypes()[0]);
 6733                    tracer.debug("Created %s, invoking setter %s with scope %s%n", userObject, setter(), scope());
 6734                    setUserObject(userObject, commandLine.factory);
 6735                    for (ArgSpec arg : args()) {
 6736                        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);
 6737                        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)
 6738                        commandLine.interpreter.parseResultBuilder.isInitializingDefaultValues = true;
 6739                        arg.applyInitialValue(tracer);
 6740                        commandLine.interpreter.applyDefault(commandLine.getCommandSpec().defaultValueProvider(), arg);
 6741                        commandLine.interpreter.parseResultBuilder.isInitializingDefaultValues = false;
 6742                    }
 6743                    for (ArgGroupSpec subgroup : subgroups()) {
 6744                        tracer.debug("Setting scope for subgroup %s with setter=%s in group %s to user object %s%n", subgroup.synopsis(), subgroup.setter(), synopsis(), userObject);
 6745                        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)
 6746                    }
 6747                } else {
 6748                    tracer.debug("No type information available for group %s: cannot create new user object. Scope for arg setters is not changed.%n", synopsis());
 6749                }
 6750                tracer.debug("Initialization complete for group %s%n", synopsis());
 6751            }
 6752
 6753            void setUserObject(Object userObject, IFactory factory) throws Exception {
 6754                if (typeInfo().isCollection()) {
 6755                    @SuppressWarnings("unchecked") Collection<Object> c = (Collection<Object>) getter().get();
 6756                    if (c == null) {
 6757                        @SuppressWarnings("unchecked")
 6758                        Collection<Object> c2 = (Collection<Object>) DefaultFactory.create(factory, typeInfo.getType());
 6759                        setter().set(c = c2);
 6760                    }
 6761                    (c).add(userObject);
 6762                } else if (typeInfo().isArray()) {
 6763                    Object old = getter().get();
 6764                    int oldSize = old == null ? 0 : Array.getLength(old);
 6765                    Object array = Array.newInstance(typeInfo().getAuxiliaryTypes()[0], oldSize + 1);
 6766                    for (int i = 0; i < oldSize; i++) {
 6767                        Array.set(array, i, Array.get(old, i));
 6768                    }
 6769                    Array.set(array, oldSize, userObject);
 6770                    setter().set(array);
 6771                } else {
 6772                    setter().set(userObject);
 6773                }
 6774            }
 6775
 6776            enum GroupValidationResult {
 6777                SUCCESS_PRESENT, SUCCESS_ABSENT,
 6778                FAILURE_PRESENT, FAILURE_ABSENT, FAILURE_PARTIAL;
 6779                static boolean containsBlockingFailure(EnumSet<GroupValidationResult> set) {
 6780                    return set.contains(FAILURE_PRESENT) || set.contains(FAILURE_PARTIAL);
 6781                }
 6782                /** FAILURE_PRESENT or FAILURE_PARTIAL */
 6783                boolean blockingFailure() { return this == FAILURE_PRESENT || this == FAILURE_PARTIAL; }
 6784                boolean present()         { return this == SUCCESS_PRESENT /*|| this == FAILURE_PRESENT*/; }
 6785                boolean success()         { return this == SUCCESS_ABSENT  || this == SUCCESS_PRESENT; }
 6786            }
 6787
 6788            private ParameterException validationException;
 6789            private GroupValidationResult validationResult;
 6790
 6791            /** Clears temporary validation state for this group and its subgroups. */
 6792            void clearValidationResult() {
 6793                validationException = null;
 6794                validationResult = null;
 6795                for (ArgGroupSpec sub : subgroups()) { sub.clearValidationResult(); }
 6796            }
 6797
 6798            /** Throws an exception if the constraints in this group are not met by the specified match. */
 6799            void validateConstraints(ParseResult parseResult) {
 6800                if (!validate()) { return; }
 6801                CommandLine commandLine = parseResult.commandSpec().commandLine();
 6802
 6803                // first validate args in this group
 6804                validationResult = validateArgs(commandLine, parseResult);
 6805                if (validationResult.blockingFailure()) {
 6806                    commandLine.interpreter.maybeThrow(validationException); // composite parent validations cannot succeed anyway
 6807                }
 6808                // then validate sub groups
 6809                EnumSet<GroupValidationResult> validationResults = validateSubgroups(parseResult);
 6810                if (GroupValidationResult.containsBlockingFailure(validationResults)) {
 6811                    commandLine.interpreter.maybeThrow(validationException); // composite parent validations cannot succeed anyway
 6812                }
 6813                List<MatchedGroup> matchedGroups = parseResult.findMatchedGroup(this);
 6814                if (matchedGroups.isEmpty()) {
 6815                    // TODO can/should we verify minimum multiplicity here?
 6816                    if (multiplicity().min > 0) {
 6817                        if (validationResult.success()) {
 6818                            validationResult = GroupValidationResult.FAILURE_ABSENT;
 6819                            validationException = new MissingParameterException(commandLine, args(),
 6820                                    "Error: Group: " + synopsis() + " must be specified " + multiplicity().min + " times but was missing");
 6821                        }
 6822                    }
 6823                }
 6824                for (MatchedGroup matchedGroup : matchedGroups) {
 6825                    int matchCount = matchedGroup.multiples().size();
 6826                    // note: matchCount == 0 if only subgroup(s) are matched for a group without args (subgroups-only)
 6827                    boolean checkMinimum = matchCount > 0 || !args().isEmpty();
 6828                    if (checkMinimum && matchCount < multiplicity().min) {
 6829                        if (validationResult.success()) {
 6830                            validationResult = matchCount == 0 ? GroupValidationResult.FAILURE_ABSENT: GroupValidationResult.FAILURE_PARTIAL;
 6831                            validationException = new MissingParameterException(commandLine, args(),
 6832                                    "Error: Group: " + synopsis() + " must be specified " + multiplicity().min + " times but was matched " + matchCount + " times");
 6833                        }
 6834                    } else if (matchCount > multiplicity().max) {
 6835                        if (!validationResult.blockingFailure()) {
 6836                            validationResult = GroupValidationResult.FAILURE_PRESENT;
 6837                            validationException = new MaxValuesExceededException(commandLine,
 6838                                    "Error: Group: " + synopsis() + " can only be specified " + multiplicity().max + " times but was matched " + matchCount + " times.");
 6839                        }
 6840                    }
 6841                    if (validationResult.blockingFailure()) {
 6842                        commandLine.interpreter.maybeThrow(validationException);
 6843                    }
 6844                }
 6845                if (validationException != null && parentGroup == null) {
 6846                    commandLine.interpreter.maybeThrow(validationException);
 6847                }
 6848            }
 6849
 6850            private EnumSet<GroupValidationResult> validateSubgroups(ParseResult parseResult) {
 6851                EnumSet<GroupValidationResult> validationResults = EnumSet.of(validationResult);
 6852                if (subgroups().isEmpty()) { return validationResults; }
 6853                for (ArgGroupSpec subgroup : subgroups()) {
 6854                    subgroup.validateConstraints(parseResult);
 6855                    validationResults.add(Assert.notNull(subgroup.validationResult, "subgroup validation result"));
 6856                    if (subgroup.validationResult.blockingFailure()) { this.validationException = subgroup.validationException; break; }
 6857                }
 6858                // now do some coarse-grained checking for exclusive subgroups
 6859                int elementCount = args().size() + subgroups().size();
 6860                int presentCount = validationResult.present() ? 1 : 0;
 6861                String exclusiveElements = "";
 6862                for (ArgGroupSpec subgroup : subgroups()) {
 6863                    if (!parseResult.findMatchedGroup(subgroup).isEmpty()) { presentCount++; }
 6864                    //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
 6865                    if (exclusiveElements.length() > 0) { exclusiveElements += " and "; }
 6866                    exclusiveElements += subgroup.synopsis();
 6867                }
 6868                validationResult = validate(parseResult.commandSpec().commandLine(), presentCount, presentCount < elementCount,
 6869                        presentCount > 0 && presentCount < elementCount, exclusiveElements, synopsis(), synopsis());
 6870                validationResults.add(validationResult);
 6871                return validationResults;
 6872            }
 6873
 6874            private GroupValidationResult validateArgs(CommandLine commandLine, ParseResult parseResult) {
 6875                if (args().isEmpty()) { return GroupValidationResult.SUCCESS_ABSENT; }
 6876                return validateArgs(commandLine, parseResult.findMatchedGroup(this));
 6877            }
 6878
 6879            private GroupValidationResult validateArgs(CommandLine commandLine, List<MatchedGroup> matchedGroups) {
 6880                if (matchedGroups.isEmpty()) {
 6881                    int presentCount = 0;
 6882                    boolean haveMissing = true;
 6883                    boolean someButNotAllSpecified = false;
 6884                    String exclusiveElements = "";
 6885                    String missingElements = ArgSpec.describe(requiredArgs());
 6886                    return validate(commandLine, presentCount, haveMissing, someButNotAllSpecified, exclusiveElements, missingElements, missingElements);
 6887                }
 6888                GroupValidationResult result = GroupValidationResult.SUCCESS_ABSENT;
 6889                Map<MatchedGroup, List<MatchedGroup>> byParent = groupByParent(matchedGroups);
 6890                for (Map.Entry<MatchedGroup, List<MatchedGroup>> entry : byParent.entrySet()) {
 6891                    List<MatchedGroup> allForOneParent = entry.getValue();
 6892                    for (MatchedGroup oneForOneParent : allForOneParent) {
 6893                        result = validateMultiples(commandLine, oneForOneParent.multiples());
 6894                        if (result.blockingFailure()) { return result; }
 6895                    }
 6896                }
 6897                return result;
 6898            }
 6899
 6900            private Map<MatchedGroup, List<MatchedGroup>> groupByParent(List<MatchedGroup> matchedGroups) {
 6901                Map<MatchedGroup, List<MatchedGroup>> result = new HashMap<MatchedGroup, List<MatchedGroup>>();
 6902                for (MatchedGroup mg : matchedGroups) {
 6903                    addValueToListInMap(result, mg.parentMatchedGroup(), mg);
 6904                }
 6905                return result;
 6906            }
 6907
 6908            private List<ParseResult.MatchedGroupMultiple> flatListMultiples(Collection<MatchedGroup> matchedGroups) {
 6909                List<ParseResult.MatchedGroupMultiple> all = new ArrayList<ParseResult.MatchedGroupMultiple>();
 6910                for (MatchedGroup matchedGroup : matchedGroups) {
 6911                    all.addAll(matchedGroup.multiples());
 6912                }
 6913                return all;
 6914            }
 6915
 6916            private GroupValidationResult validateMultiples(CommandLine commandLine, List<ParseResult.MatchedGroupMultiple> multiples) {
 6917                Set<ArgSpec> intersection = new LinkedHashSet<ArgSpec>(this.args());
 6918                Set<ArgSpec> missing = new LinkedHashSet<ArgSpec>(this.requiredArgs());
 6919                Set<ArgSpec> found = new LinkedHashSet<ArgSpec>();
 6920                for (ParseResult.MatchedGroupMultiple multiple : multiples) {
 6921                    found.addAll(multiple.matchedValues.keySet());
 6922                    missing.removeAll(multiple.matchedValues.keySet());
 6923                }
 6924                intersection.retainAll(found);
 6925                int presentCount = intersection.size();
 6926                boolean haveMissing = !missing.isEmpty();
 6927                boolean someButNotAllSpecified = haveMissing && !intersection.isEmpty();
 6928                String exclusiveElements = ArgSpec.describe(intersection);
 6929                String requiredElements = ArgSpec.describe(requiredArgs());
 6930                String missingElements = ArgSpec.describe(missing);
 6931
 6932                return validate(commandLine, presentCount, haveMissing, someButNotAllSpecified, exclusiveElements, requiredElements, missingElements);
 6933            }
 6934
 6935            private GroupValidationResult validate(CommandLine commandLine, int presentCount, boolean haveMissing, boolean someButNotAllSpecified, String exclusiveElements, String requiredElements, String missingElements) {
 6936                if (exclusive()) {
 6937                    if (presentCount > 1) {
 6938                        validationException = new MutuallyExclusiveArgsException(commandLine,
 6939                                "Error: " + exclusiveElements + " are mutually exclusive (specify only one)");
 6940                        return GroupValidationResult.FAILURE_PRESENT;
 6941                    }
 6942                    // check that exactly one member was matched
 6943                    if (multiplicity().min > 0 && presentCount < 1) {
 6944                        validationException = new MissingParameterException(commandLine, args(),
 6945                                "Error: Missing required argument (specify one of these): " + requiredElements);
 6946                        return GroupValidationResult.FAILURE_ABSENT;
 6947                    }
 6948                    return GroupValidationResult.SUCCESS_PRESENT;
 6949                } else { // co-occurring group
 6950                    if (someButNotAllSpecified) {
 6951                        validationException = new MissingParameterException(commandLine, args(),
 6952                                "Error: Missing required argument(s): " + missingElements);
 6953                        return GroupValidationResult.FAILURE_PARTIAL;
 6954                    }
 6955                    if ((multiplicity().min > 0 && haveMissing)) {
 6956                        validationException = new MissingParameterException(commandLine, args(),
 6957                                "Error: Missing required argument(s): " + missingElements);
 6958                        return GroupValidationResult.FAILURE_ABSENT;
 6959                    }
 6960                    return haveMissing ? GroupValidationResult.SUCCESS_ABSENT : GroupValidationResult.SUCCESS_PRESENT;
 6961                }
 6962            }
 6963
 6964            /** Builder responsible for creating valid {@code ArgGroupSpec} objects.
 6965             * @since 4.0 */
 6966            public static class Builder {
 6967                private IGetter getter;
 6968                private ISetter setter;
 6969                private IScope scope;
 6970                private ITypeInfo typeInfo;
 6971                private String heading;
 6972                private String headingKey;
 6973                private boolean exclusive  = true;
 6974                private Range multiplicity = Range.valueOf("0..1");
 6975                private boolean validate   = true;
 6976                private int order          = DEFAULT_ORDER;
 6977                private List<ArgSpec> args = new ArrayList<ArgSpec>();
 6978                private List<ArgGroupSpec> subgroups = new ArrayList<ArgGroupSpec>();
 6979
 6980                // for topological sorting; private only
 6981                private Boolean topologicalSortDone;
 6982                private List<Builder> compositesReferencingMe = new ArrayList<Builder>();
 6983
 6984                Builder() { }
 6985                Builder(IAnnotatedElement source) {
 6986                    typeInfo = source.getTypeInfo();
 6987                    getter = source.getter();
 6988                    setter = source.setter();
 6989                    scope = source.scope();
 6990                }
 6991
 6992                /** Updates this builder from the specified annotation values.
 6993                 * @param group annotation values
 6994                 * @return this builder for method chaining */
 6995                public Builder updateArgGroupAttributes(ArgGroup group) {
 6996                    return this
 6997                            .heading(group.heading())
 6998                            .headingKey(group.headingKey())
 6999                            .exclusive(group.exclusive())
 7000                            .multiplicity(group.multiplicity())
 7001                            .validate(group.validate())
 7002                            .order(group.order());
 7003                }
 7004
 7005                /** Returns a valid {@code ArgGroupSpec} instance. */
 7006                public ArgGroupSpec build() { return new ArgGroupSpec(this); }
 7007
 7008                /** Returns whether this is a mutually exclusive group; {@code true} by default.
 7009                 * If {@code false}, this is a co-occurring group. Ignored if {@link #validate()} is {@code false}.
 7010                 * @see ArgGroup#exclusive() */
 7011                public boolean exclusive() { return exclusive; }
 7012                /** Sets whether this is a mutually exclusive group; {@code true} by default.
 7013                 * If {@code false}, this is a co-occurring group. Ignored if {@link #validate()} is {@code false}.
 7014                 * @see ArgGroup#exclusive() */
 7015                public Builder exclusive(boolean newValue) { exclusive = newValue; return this; }
 7016
 7017                /** Returns the multiplicity of this group: how many occurrences it may have on the command line; {@code "0..1"} (optional) by default.
 7018                 * A group can be made required by specifying a multiplicity of {@code "1"}. For a group of mutually exclusive arguments,
 7019                 * being required means that one of the arguments in the group must appear on the command line, or a MissingParameterException is thrown.
 7020                 * For a group of co-occurring arguments, being required means that all arguments in the group must appear on the command line.
 7021                 * Ignored if {@link #validate()} is {@code false}.
 7022                 * @see ArgGroup#multiplicity() */
 7023                public Range multiplicity() { return multiplicity; }
 7024                /** Sets the multiplicity of this group: how many occurrences it may have on the command line; {@code "0..1"} (optional) by default.
 7025                 * A group can be made required by specifying a multiplicity of {@code "1"}. For a group of mutually exclusive arguments,
 7026                 * being required means that one of the arguments in the group must appear on the command line, or a MissingParameterException is thrown.
 7027                 * For a group of co-occurring arguments, being required means that all arguments in the group must appear on the command line.
 7028                 * Ignored if {@link #validate()} is {@code false}.
 7029                 * @see ArgGroup#multiplicity() */
 7030                public Builder multiplicity(String newValue) { return multiplicity(Range.valueOf(newValue)); }
 7031                /** Sets the multiplicity of this group: how many occurrences it may have on the command line; {@code "0..1"} (optional) by default.
 7032                 * A group can be made required by specifying a multiplicity of {@code "1"}. For a group of mutually exclusive arguments,
 7033                 * being required means that one of the arguments in the group must appear on the command line, or a MissingParameterException is thrown.
 7034                 * For a group of co-occurring arguments, being required means that all arguments in the group must appear on the command line.
 7035                 * Ignored if {@link #validate()} is {@code false}.
 7036                 * @see ArgGroup#multiplicity() */
 7037                public Builder multiplicity(Range newValue) { multiplicity = newValue; return this; }
 7038
 7039                /** Returns whether picocli should validate the rules of this group:
 7040                 * for a mutually exclusive group this means that no more than one arguments in the group is specified on the command line;
 7041                 * for a co-ocurring group this means that all arguments in the group are specified on the command line.
 7042                 * {@code true} by default.
 7043                 * @see ArgGroup#validate() */
 7044                public boolean validate() { return validate; }
 7045                /** Sets whether picocli should validate the rules of this group:
 7046                 * for a mutually exclusive group this means that no more than one arguments in the group is specified on the command line;
 7047                 * for a co-ocurring group this means that all arguments in the group are specified on the command line.
 7048                 * {@code true} by default.
 7049                 * @see ArgGroup#validate() */
 7050                public Builder validate(boolean newValue) { validate = newValue; return this; }
 7051
 7052                /** Returns the position in the options list in the usage help message at which this group should be shown.
 7053                 * Options with a lower number are shown before options with a higher number.
 7054                 * This attribute is only honored if {@link UsageMessageSpec#sortOptions()} is {@code false} for this command.*/
 7055                public int order() { return order; }
 7056
 7057                /** Sets the position in the options list in the usage help message at which this group should be shown, and returns this builder. */
 7058                public Builder order(int order) { this.order = order; return this; }
 7059
 7060                /** Returns the heading of this group, used when generating the usage documentation.
 7061                 * @see ArgGroup#heading() */
 7062                public String heading() { return heading; }
 7063
 7064                /** Sets the heading of this group (may be {@code null}), used when generating the usage documentation.
 7065                 * @see ArgGroup#heading() */
 7066                public Builder heading(String newValue) { this.heading = newValue; return this; }
 7067
 7068                /** Returns the heading key of this group, used to get the heading from a resource bundle.
 7069                 * @see ArgGroup#headingKey()  */
 7070                public String headingKey() { return headingKey; }
 7071                /** Sets the heading key of this group, used to get the heading from a resource bundle.
 7072                 * @see ArgGroup#headingKey()  */
 7073                public Builder headingKey(String newValue) { this.headingKey = newValue; return this; }
 7074
 7075                /** Returns the type info for the annotated program element associated with this group.
 7076                 * @return type information that does not require {@code Class} objects and be constructed both at runtime and compile time
 7077                 */
 7078                public ITypeInfo typeInfo()    { return typeInfo; }
 7079                /** Sets the type info for the annotated program element associated with this group, and returns this builder.
 7080                 * @param newValue type information that does not require {@code Class} objects and be constructed both at runtime and compile time
 7081                 */
 7082                public Builder typeInfo(ITypeInfo newValue) { this.typeInfo = newValue; return this; }
 7083
 7084                /** Returns the {@link IGetter} that is responsible for supplying the value of the annotated program element associated with this group. */
 7085                public IGetter getter()        { return getter; }
 7086                /** Sets the {@link IGetter} that is responsible for getting the value of the annotated program element associated with this group, and returns this builder. */
 7087                public Builder getter(IGetter getter)       { this.getter = getter; return this; }
 7088
 7089                /** Returns the {@link ISetter} that is responsible for modifying the value of the annotated program element associated with this group. */
 7090                public ISetter setter()        { return setter; }
 7091                /** Sets the {@link ISetter} that is responsible for modifying the value of the annotated program element associated with this group, and returns this builder. */
 7092                public Builder setter(ISetter setter)       { this.setter = setter; return this; }
 7093
 7094                /** 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. */
 7095                public IScope scope()          { return scope; }
 7096                /** 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. */
 7097                public Builder scope(IScope scope)          { this.scope = scope; return this; }
 7098
 7099                /** Adds the specified argument to the list of options and positional parameters that depend on this group. */
 7100                public Builder addArg(ArgSpec arg) { args.add(arg); return this; }
 7101
 7102                /** Returns the list of options and positional parameters that depend on this group.*/
 7103                public List<ArgSpec> args() { return args; }
 7104
 7105                /** Adds the specified group to the list of subgroups that this group is composed of. */
 7106                public Builder addSubgroup(ArgGroupSpec group) { subgroups.add(group); return this; }
 7107
 7108                /** Returns the list of subgroups that this group is composed of.*/
 7109                public List<ArgGroupSpec> subgroups() { return subgroups; }
 7110            }
 7111        }
 7112
 7113        /** This class allows applications to specify a custom binding that will be invoked for unmatched arguments.
 7114         * A binding can be created with a {@code ISetter} that consumes the unmatched arguments {@code String[]}, or with a
 7115         * {@code IGetter} that produces a {@code Collection<String>} that the unmatched arguments can be added to.
 7116         * @since 3.0 */
 7117        public static class UnmatchedArgsBinding {
 7118            private final IGetter getter;
 7119            private final ISetter setter;
 7120
 7121            /** Creates a {@code UnmatchedArgsBinding} for a setter that consumes {@code String[]} objects.
 7122             * @param setter consumes the String[] array with unmatched arguments. */
 7123            public static UnmatchedArgsBinding forStringArrayConsumer(ISetter setter) { return new UnmatchedArgsBinding(null, setter); }
 7124
 7125            /** Creates a {@code UnmatchedArgsBinding} for a getter that produces a {@code Collection<String>} that the unmatched arguments can be added to.
 7126             * @param getter supplies a {@code Collection<String>} that the unmatched arguments can be added to. */
 7127            public static UnmatchedArgsBinding forStringCollectionSupplier(IGetter getter) { return new UnmatchedArgsBinding(getter, null); }
 7128
 7129            private UnmatchedArgsBinding(IGetter getter, ISetter setter) {
 7130                if (getter == null && setter == null) { throw new IllegalArgumentException("Getter and setter cannot both be null"); }
 7131                this.setter = setter;
 7132                this.getter = getter;
 7133            }
 7134            /** Returns the getter responsible for producing a {@code Collection} that the unmatched arguments can be added to. */
 7135            public IGetter getter() { return getter; }
 7136            /** Returns the setter responsible for consuming the unmatched arguments. */
 7137            public ISetter setter() { return setter; }
 7138            void addAll(String[] unmatched) {
 7139                if (setter != null) {
 7140                    try {
 7141                        setter.set(unmatched);
 7142                    } catch (Exception ex) {
 7143                        throw new PicocliException(String.format("Could not invoke setter (%s) with unmatched argument array '%s': %s", setter, Arrays.toString(unmatched), ex), ex);
 7144                    }
 7145                }
 7146                if (getter != null) {
 7147                    try {
 7148                        Collection<String> collection = getter.get();
 7149                        Assert.notNull(collection, "getter returned null Collection");
 7150                        collection.addAll(Arrays.asList(unmatched));
 7151                    } catch (Exception ex) {
 7152                        throw new PicocliException(String.format("Could not add unmatched argument array '%s' to collection returned by getter (%s): %s",
 7153                                Arrays.toString(unmatched), getter, ex), ex);
 7154                    }
 7155                }
 7156            }
 7157        }
 7158        /** Command method parameter, similar to java.lang.reflect.Parameter (not available before Java 8).
 7159         * @since 4.0 */
 7160        public static class MethodParam extends AccessibleObject {
 7161            final Method method;
 7162            final int paramIndex;
 7163            final String name;
 7164            int position;
 7165
 7166            public MethodParam(Method method, int paramIndex) {
 7167                this.method = method;
 7168                this.paramIndex = paramIndex;
 7169                String tmp = "arg" + paramIndex;
 7170                try {
 7171                    Method getParameters = Method.class.getMethod("getParameters");
 7172                    Object parameters = getParameters.invoke(method);
 7173                    Object parameter = Array.get(parameters, paramIndex);
 7174                    tmp = (String) Class.forName("java.lang.reflect.Parameter").getDeclaredMethod("getName").invoke(parameter);
 7175                } catch (Exception ignored) {}
 7176                this.name = tmp;
 7177            }
 7178            public Type getParameterizedType() { return method.getGenericParameterTypes()[paramIndex]; }
 7179            public String getName() { return name; }
 7180            public Class<?> getType() { return method.getParameterTypes()[paramIndex]; }
 7181            public Method getDeclaringExecutable() { return method; }
 7182            @Override public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
 7183                for (Annotation annotation : getDeclaredAnnotations()) {
 7184                    if (annotationClass.isAssignableFrom(annotation.getClass())) { return annotationClass.cast(annotation); }
 7185                }
 7186                return null;
 7187            }
 7188            @Override public Annotation[] getDeclaredAnnotations() { return method.getParameterAnnotations()[paramIndex]; }
 7189            @Override public void setAccessible(boolean flag) throws SecurityException { method.setAccessible(flag); }
 7190            @Override public boolean isAccessible() throws SecurityException { return method.isAccessible(); }
 7191            @Override public String toString() { return method.toString() + ":" + getName(); }
 7192        }
 7193
 7194        /** Encapculates type information for an option or parameter to make this information available both at runtime
 7195         * and at compile time (when {@code Class} values are not available).
 7196         * Most of the methods in this interface (but not all!) are safe to use by annotation processors.
 7197         * @since 4.0
 7198         */
 7199        public interface ITypeInfo {
 7200            /** Returns {@code true} if {@link #getType()} is {@code boolean} or {@code java.lang.Boolean}. */
 7201            boolean isBoolean();
 7202            /** Returns {@code true} if {@link #getType()} is an array, map or collection. */
 7203            boolean isMultiValue();
 7204            boolean isArray();
 7205            boolean isCollection();
 7206            boolean isMap();
 7207            /** Returns {@code true} if {@link #getType()} is an enum. */
 7208            boolean isEnum();
 7209            List<String> getEnumConstantNames();
 7210            String getClassName();
 7211            String getClassSimpleName();
 7212            /** Returns type information of components or elements of a {@link #isMultiValue() multivalue} type. */
 7213            List<ITypeInfo> getAuxiliaryTypeInfos();
 7214            /** 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>}. */
 7215            List<String> getActualGenericTypeArguments();
 7216
 7217            /** Returns the class that the option or parameter value should be converted to when matched on the command
 7218             * line. This method is <em>not</em> safe for annotation processors to use.
 7219             * @return the class that the option or parameter value should be converted to
 7220             */
 7221            Class<?> getType();
 7222            /** Returns the component class of an array, or the parameter type of a generic Collection, or the parameter
 7223             * types of the key and the value of a generic Map.
 7224             * This method is <em>not</em> safe for annotation processors to use.
 7225             * @return the component type or types of an array, Collection or Map type
 7226             */
 7227            Class<?>[] getAuxiliaryTypes();
 7228        }
 7229        static class RuntimeTypeInfo implements ITypeInfo {
 7230            private final Class<?> type;
 7231            private final Class<?>[] auxiliaryTypes;
 7232            private final List<String> actualGenericTypeArguments;
 7233
 7234            RuntimeTypeInfo(Class<?> type, Class<?>[] auxiliaryTypes, List<String> actualGenericTypeArguments) {
 7235                this.type = Assert.notNull(type, "type");
 7236                this.auxiliaryTypes = Assert.notNull(auxiliaryTypes, "auxiliaryTypes").clone();
 7237                this.actualGenericTypeArguments = actualGenericTypeArguments == null ? Collections.<String>emptyList() : Collections.unmodifiableList(new ArrayList<String>(actualGenericTypeArguments));
 7238            }
 7239
 7240            static ITypeInfo createForAuxType(Class<?> type) {
 7241                return create(type, new Class[0], (Type) null, Range.valueOf("1"), String.class);
 7242            }
 7243            public static ITypeInfo create(Class<?> type,
 7244                                           Class<?>[] annotationTypes,
 7245                                           Type genericType,
 7246                                           Range arity,
 7247                                           Class<?> defaultType) {
 7248                Class<?>[] auxiliaryTypes = RuntimeTypeInfo.inferTypes(type, annotationTypes, genericType);
 7249                List<String> actualGenericTypeArguments = new ArrayList<String>();
 7250                if (genericType instanceof ParameterizedType)  {
 7251                    Class[] declaredTypeParameters = extractTypeParameters((ParameterizedType) genericType);
 7252                    for (Class<?> c : declaredTypeParameters) { actualGenericTypeArguments.add(c.getName()); }
 7253                }
 7254                return create(type, auxiliaryTypes, actualGenericTypeArguments, arity, defaultType);
 7255            }
 7256
 7257            public static ITypeInfo create(Class<?> type, Class<?>[] auxiliaryTypes, List<String> actualGenericTypeArguments, Range arity, Class<?> defaultType) {
 7258                if (type == null) {
 7259                    if (auxiliaryTypes == null || auxiliaryTypes.length == 0) {
 7260                        if (arity.isVariable || arity.max > 1) {
 7261                            type = String[].class;
 7262                        } else if (arity.max == 1) {
 7263                            type = String.class;
 7264                        } else {
 7265                            type = defaultType;
 7266                        }
 7267                    } else {
 7268                        type = auxiliaryTypes[0];
 7269                    }
 7270                }
 7271                if (auxiliaryTypes == null || auxiliaryTypes.length == 0) {
 7272                    if (type.isArray()) {
 7273                        auxiliaryTypes = new Class<?>[] {type.getComponentType()};
 7274                    } else if (Collection.class.isAssignableFrom(type)) { // type is a collection but element type is unspecified
 7275                        auxiliaryTypes = new Class<?>[] {String.class}; // use String elements
 7276                    } else if (Map.class.isAssignableFrom(type)) { // type is a map but element type is unspecified
 7277                        auxiliaryTypes = new Class<?>[] {String.class, String.class}; // use String keys and String values
 7278                    } else {
 7279                        auxiliaryTypes = new Class<?>[] {type};
 7280                    }
 7281                }
 7282                return new RuntimeTypeInfo(type, auxiliaryTypes, actualGenericTypeArguments);
 7283            }
 7284            static Class<?>[] inferTypes(Class<?> propertyType, Class<?>[] annotationTypes, Type genericType) {
 7285                if (annotationTypes != null && annotationTypes.length > 0) { return annotationTypes; }
 7286                if (propertyType.isArray()) { return new Class<?>[] { propertyType.getComponentType() }; }
 7287                if (CommandLine.isMultiValue(propertyType)) {
 7288                    if (genericType instanceof ParameterizedType) {// e.g. Map<Long, ? extends Number>
 7289                        return extractTypeParameters((ParameterizedType) genericType);
 7290                    }
 7291                    return new Class<?>[] {String.class, String.class}; // field is multi-value but not ParameterizedType
 7292                }
 7293                return new Class<?>[] {propertyType}; // not a multi-value field
 7294            }
 7295
 7296            static Class<?>[] extractTypeParameters(ParameterizedType genericType) {
 7297                ParameterizedType parameterizedType = genericType;
 7298                Type[] paramTypes = parameterizedType.getActualTypeArguments(); // e.g. ? extends Number
 7299                Class<?>[] result = new Class<?>[paramTypes.length];
 7300                for (int i = 0; i < paramTypes.length; i++) {
 7301                    if (paramTypes[i] instanceof Class) { result[i] = (Class<?>) paramTypes[i]; continue; } // e.g. Long
 7302                    if (paramTypes[i] instanceof WildcardType) { // e.g. ? extends Number
 7303                        WildcardType wildcardType = (WildcardType) paramTypes[i];
 7304                        Type[] lower = wildcardType.getLowerBounds(); // e.g. []
 7305                        if (lower.length > 0 && lower[0] instanceof Class) { result[i] = (Class<?>) lower[0]; continue; }
 7306                        Type[] upper = wildcardType.getUpperBounds(); // e.g. Number
 7307                        if (upper.length > 0 && upper[0] instanceof Class) { result[i] = (Class<?>) upper[0]; continue; }
 7308                    }
 7309                    Arrays.fill(result, String.class); return result; // too convoluted generic type, giving up
 7310                }
 7311                return result; // we inferred all types from ParameterizedType
 7312            }
 7313
 7314            public boolean isBoolean()            { return auxiliaryTypes[0] == boolean.class || auxiliaryTypes[0] == Boolean.class; }
 7315            public boolean isMultiValue()         { return CommandLine.isMultiValue(type); }
 7316            public boolean isArray()              { return type.isArray(); }
 7317            public boolean isCollection()         { return Collection.class.isAssignableFrom(type); }
 7318            public boolean isMap()                { return Map.class.isAssignableFrom(type); }
 7319            public boolean isEnum()               { return auxiliaryTypes[0].isEnum(); }
 7320            public String getClassName()          { return type.getName(); }
 7321            public String getClassSimpleName()    { return type.getSimpleName(); }
 7322            public Class<?> getType()             { return type; }
 7323            public Class<?>[] getAuxiliaryTypes() { return auxiliaryTypes; }
 7324            public List<String> getActualGenericTypeArguments() { return actualGenericTypeArguments; }
 7325
 7326            public List<ITypeInfo> getAuxiliaryTypeInfos()  {
 7327                List<ITypeInfo> result = new ArrayList<ITypeInfo>();
 7328                for (Class<?> c : auxiliaryTypes) { result.add(createForAuxType(c)); }
 7329                return result;
 7330            }
 7331            public List<String> getEnumConstantNames() {
 7332                if (!isEnum()) { return Collections.emptyList(); }
 7333                List<String> result = new ArrayList<String>();
 7334                for (Object c : auxiliaryTypes[0].getEnumConstants()) { result.add(c.toString()); }
 7335                return result;
 7336            }
 7337
 7338            public boolean equals(Object obj) {
 7339                if (obj == this) { return true; }
 7340                if (!(obj instanceof RuntimeTypeInfo)) { return false; }
 7341                RuntimeTypeInfo other = (RuntimeTypeInfo) obj;
 7342                return Arrays.equals(other.auxiliaryTypes, auxiliaryTypes) && type.equals(other.type);
 7343            }
 7344            public int hashCode() {
 7345                return Arrays.hashCode(auxiliaryTypes) + 37 * Assert.hashCode(type);
 7346            }
 7347            public String toString() {
 7348                return String.format("RuntimeTypeInfo(%s, aux=%s, collection=%s, map=%s)",
 7349                        type.getCanonicalName(), Arrays.toString(auxiliaryTypes), isCollection(), isMap());
 7350            }
 7351        }
 7352        /** Internal interface to allow annotation processors to construct a command model at compile time.
 7353         * @since 4.0 */
 7354        public interface IAnnotatedElement {
 7355            Object userObject();
 7356            boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
 7357            <T extends Annotation> T getAnnotation(Class<T> annotationClass);
 7358            String getName();
 7359            String getMixinName();
 7360            boolean isArgSpec();
 7361            boolean isOption();
 7362            boolean isParameter();
 7363            boolean isArgGroup();
 7364            boolean isMixin();
 7365            boolean isUnmatched();
 7366            boolean isInjectSpec();
 7367            boolean isMultiValue();
 7368            boolean hasInitialValue();
 7369            boolean isMethodParameter();
 7370            int getMethodParamPosition();
 7371            CommandLine.Model.IScope scope();
 7372            CommandLine.Model.IGetter getter();
 7373            CommandLine.Model.ISetter setter();
 7374            ITypeInfo getTypeInfo();
 7375            String getToString();
 7376        }
 7377
 7378        static class TypedMember implements IAnnotatedElement {
 7379            final AccessibleObject accessible;
 7380            final String name;
 7381            final ITypeInfo typeInfo;
 7382            boolean hasInitialValue;
 7383            private IScope scope;
 7384            private IGetter getter;
 7385            private ISetter setter;
 7386            static TypedMember createIfAnnotated(Field field, IScope scope) {
 7387                return isAnnotated(field) ? new TypedMember(field, scope) : null;
 7388            }
 7389            static boolean isAnnotated(AnnotatedElement e) {
 7390                return false
 7391                        || e.isAnnotationPresent(Option.class)
 7392                        || e.isAnnotationPresent(Parameters.class)
 7393                        || e.isAnnotationPresent(ArgGroup.class)
 7394                        || e.isAnnotationPresent(Unmatched.class)
 7395                        || e.isAnnotationPresent(Mixin.class)
 7396                        || e.isAnnotationPresent(Spec.class)
 7397                        || e.isAnnotationPresent(ParentCommand.class);
 7398            }
 7399            TypedMember(Field field) {
 7400                accessible = Assert.notNull(field, "field");
 7401                accessible.setAccessible(true);
 7402                name = field.getName();
 7403                typeInfo = createTypeInfo(field.getType(), field.getGenericType());
 7404                hasInitialValue = true;
 7405            }
 7406            private TypedMember(Field field, IScope scope) {
 7407                this(field);
 7408                Object obj = ObjectScope.tryGet(scope);
 7409                if (obj != null && Proxy.isProxyClass(obj.getClass())) {
 7410                    throw new InitializationException("Invalid picocli annotation on interface field");
 7411                }
 7412                FieldBinding binding = new FieldBinding(scope, field);
 7413                getter = binding; setter = binding;
 7414                this.scope = scope;
 7415                hasInitialValue &= obj != null ;
 7416            }
 7417            static TypedMember createIfAnnotated(Method method, IScope scope, CommandSpec spec) {
 7418                return isAnnotated(method) ? new TypedMember(method, scope, spec) : null;
 7419            }
 7420            private TypedMember(Method method, IScope scope, CommandSpec spec) {
 7421                accessible = Assert.notNull(method, "method");
 7422                accessible.setAccessible(true);
 7423                name = propertyName(method.getName());
 7424                Class<?>[] parameterTypes = method.getParameterTypes();
 7425                boolean isGetter = parameterTypes.length == 0 && method.getReturnType() != Void.TYPE && method.getReturnType() != Void.class;
 7426                boolean isSetter = parameterTypes.length > 0;
 7427                if (isSetter == isGetter) { throw new InitializationException("Invalid method, must be either getter or setter: " + method); }
 7428                if (isGetter) {
 7429                    hasInitialValue = true;
 7430                    typeInfo = createTypeInfo(method.getReturnType(), method.getGenericReturnType());
 7431                    Object proxy = ObjectScope.tryGet(scope);
 7432                    if (Proxy.isProxyClass(proxy.getClass())) {
 7433                        PicocliInvocationHandler handler = (PicocliInvocationHandler) Proxy.getInvocationHandler(proxy);
 7434                        PicocliInvocationHandler.ProxyBinding binding = handler.new ProxyBinding(method);
 7435                        getter = binding; setter = binding;
 7436                        initializeInitialValue(method);
 7437                    } else {
 7438                        //throw new IllegalArgumentException("Getter method but not a proxy: " + scope + ": " + method);
 7439                        MethodBinding binding = new MethodBinding(scope, method, spec);
 7440                        getter = binding; setter = binding;
 7441                    }
 7442                } else {
 7443                    hasInitialValue = false;
 7444                    typeInfo = createTypeInfo(parameterTypes[0], method.getGenericParameterTypes()[0]);
 7445                    MethodBinding binding = new MethodBinding(scope, method, spec);
 7446                    getter = binding; setter = binding;
 7447                }
 7448            }
 7449            TypedMember(MethodParam param, IScope scope) {
 7450                accessible = Assert.notNull(param, "command method parameter");
 7451                accessible.setAccessible(true);
 7452                name = param.getName();
 7453                typeInfo = createTypeInfo(param.getType(), param.getParameterizedType());
 7454                // bind parameter
 7455                ObjectBinding binding = new ObjectBinding();
 7456                getter = binding; setter = binding;
 7457                initializeInitialValue(param);
 7458                hasInitialValue = true;
 7459            }
 7460
 7461            private ITypeInfo createTypeInfo(Class<?> type, Type genericType) {
 7462                Range arity = null;
 7463                if (isOption())    { arity = Range.valueOf(getAnnotation(Option.class).arity()); }
 7464                if (isParameter()) { arity = Range.valueOf(getAnnotation(Parameters.class).arity()); }
 7465                if (arity == null || arity.isUnspecified) {
 7466                    if (isOption()) {
 7467                        arity = (type == null || isBoolean(type)) ? Range.valueOf("0") : Range.valueOf("1");
 7468                    } else {
 7469                        arity = Range.valueOf("1");
 7470                    }
 7471                    arity = arity.unspecified(true);
 7472                }
 7473                return RuntimeTypeInfo.create(type, annotationTypes(), genericType, arity, (isOption() ? boolean.class : String.class));
 7474            }
 7475
 7476            private void initializeInitialValue(Object arg) {
 7477                Class<?> type = typeInfo.getType();
 7478                try {
 7479                    if      (type == Boolean.TYPE  ) { setter.set(false); }
 7480                    else if (type == Byte.TYPE     ) { setter.set(Byte.valueOf((byte) 0)); }
 7481                    else if (type == Character.TYPE) { setter.set(Character.valueOf((char) 0)); }
 7482                    else if (type == Short.TYPE    ) { setter.set(Short.valueOf((short) 0)); }
 7483                    else if (type == Integer.TYPE  ) { setter.set(Integer.valueOf(0)); }
 7484                    else if (type == Long.TYPE     ) { setter.set(Long.valueOf(0L)); }
 7485                    else if (type == Float.TYPE    ) { setter.set(Float.valueOf(0f)); }
 7486                    else if (type == Double.TYPE   ) { setter.set(Double.valueOf(0d)); }
 7487                    else {                             setter.set(null); }
 7488                } catch (Exception ex) {
 7489                    throw new InitializationException("Could not set initial value for " + arg + ": " + ex.toString(), ex);
 7490                }
 7491            }
 7492            public Object userObject()      { return accessible; }
 7493            public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { return accessible.isAnnotationPresent(annotationClass); }
 7494            public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { return accessible.getAnnotation(annotationClass); }
 7495            public String getName()         { return name; }
 7496            public boolean isArgSpec()      { return isOption() || isParameter() || (isMethodParameter() && !isMixin()); }
 7497            public boolean isOption()       { return isAnnotationPresent(Option.class); }
 7498            public boolean isParameter()    { return isAnnotationPresent(Parameters.class); }
 7499            public boolean isArgGroup()     { return isAnnotationPresent(ArgGroup.class); }
 7500            public boolean isMixin()        { return isAnnotationPresent(Mixin.class); }
 7501            public boolean isUnmatched()    { return isAnnotationPresent(Unmatched.class); }
 7502            public boolean isInjectSpec()   { return isAnnotationPresent(Spec.class); }
 7503            public boolean isMultiValue()   { return CommandLine.isMultiValue(getType()); }
 7504            public IScope  scope()          { return scope; }
 7505            public IGetter getter()         { return getter; }
 7506            public ISetter setter()         { return setter; }
 7507            public ITypeInfo getTypeInfo()  { return typeInfo; }
 7508            public Class<?> getType()       { return typeInfo.getType(); }
 7509            public Class<?>[] getAuxiliaryTypes() { return typeInfo.getAuxiliaryTypes(); }
 7510            private Class<?>[] annotationTypes() {
 7511                if (isOption())    { return getAnnotation(Option.class).type(); }
 7512                if (isParameter()) { return getAnnotation(Parameters.class).type(); }
 7513                return new Class[0];
 7514            }
 7515            public String toString() { return accessible.toString(); }
 7516            public String getToString()  {
 7517                if (isMixin()) { return abbreviate("mixin from member " + toGenericString()); }
 7518                return (accessible instanceof Field ? "field " : accessible instanceof Method ? "method " : accessible.getClass().getSimpleName() + " ") + abbreviate(toGenericString());
 7519            }
 7520            public String toGenericString() { return accessible instanceof Field ? ((Field) accessible).toGenericString() : accessible instanceof Method ? ((Method) accessible).toGenericString() : ((MethodParam)accessible).toString(); }
 7521            public boolean hasInitialValue()    { return hasInitialValue; }
 7522            public boolean isMethodParameter()  { return accessible instanceof MethodParam; }
 7523            public int getMethodParamPosition() { return isMethodParameter() ? ((MethodParam) accessible).position : -1; }
 7524            public String getMixinName()    {
 7525                String annotationName = getAnnotation(Mixin.class).name();
 7526                return empty(annotationName) ? getName() : annotationName;
 7527            }
 7528            static String propertyName(String methodName) {
 7529                if (methodName.length() > 3 && (methodName.startsWith("get") || methodName.startsWith("set"))) { return decapitalize(methodName.substring(3)); }
 7530                return decapitalize(methodName);
 7531            }
 7532            private static String decapitalize(String name) {
 7533                if (name == null || name.length() == 0) { return name; }
 7534                char[] chars = name.toCharArray();
 7535                chars[0] = Character.toLowerCase(chars[0]);
 7536                return new String(chars);
 7537            }
 7538            static String abbreviate(String text) {
 7539                return text.replace("private ", "")
 7540                        .replace("protected ", "")
 7541                        .replace("public ", "")
 7542                        .replace("java.lang.", "");
 7543            }
 7544        }
 7545
 7546        /** Utility class for getting resource bundle strings.
 7547         * Enhances the standard <a href="https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>
 7548         * with support for String arrays and qualified keys: keys that may or may not be prefixed with the fully qualified command name.
 7549         * <p>Example properties resource bundle:</p><pre>
 7550         * # Usage Help Message Sections
 7551         * # ---------------------------
 7552         * # Numbered resource keys can be used to create multi-line sections.
 7553         * usage.headerHeading = This is my app. There are other apps like it but this one is mine.%n
 7554         * usage.header   = header first line
 7555         * usage.header.0 = header second line
 7556         * usage.descriptionHeading = Description:%n
 7557         * usage.description.0 = first line
 7558         * usage.description.1 = second line
 7559         * usage.description.2 = third line
 7560         * usage.synopsisHeading = Usage:&#92;u0020
 7561         * # Leading whitespace is removed by default. Start with &#92;u0020 to keep the leading whitespace.
 7562         * usage.customSynopsis.0 =      Usage: ln [OPTION]... [-T] TARGET LINK_NAME   (1st form)
 7563         * usage.customSynopsis.1 = &#92;u0020 or:  ln [OPTION]... TARGET                  (2nd form)
 7564         * usage.customSynopsis.2 = &#92;u0020 or:  ln [OPTION]... TARGET... DIRECTORY     (3rd form)
 7565         * # Headings can contain the %n character to create multi-line values.
 7566         * usage.parameterListHeading = %nPositional parameters:%n
 7567         * usage.optionListHeading = %nOptions:%n
 7568         * usage.commandListHeading = %nCommands:%n
 7569         * usage.footerHeading = Powered by picocli%n
 7570         * usage.footer = footer
 7571         *
 7572         * # Option Descriptions
 7573         * # -------------------
 7574         * # Use numbered keys to create multi-line descriptions.
 7575         * help = Show this help message and exit.
 7576         * version = Print version information and exit.
 7577         * </pre>
 7578         * <p>Resources for multiple commands can be specified in a single ResourceBundle. Keys and their value can be
 7579         * shared by multiple commands (so you don't need to repeat them for every command), but keys can be prefixed with
 7580         * {@code fully qualified command name + "."} to specify different values for different commands.
 7581         * The most specific key wins. For example: </p>
 7582         * <pre>
 7583         * jfrog.rt.usage.header = Artifactory commands
 7584         * jfrog.rt.config.usage.header = Configure Artifactory details.
 7585         * jfrog.rt.upload.usage.header = Upload files.
 7586         *
 7587         * jfrog.bt.usage.header = Bintray commands
 7588         * jfrog.bt.config.usage.header = Configure Bintray details.
 7589         * jfrog.bt.upload.usage.header = Upload files.
 7590         *
 7591         * # shared between all commands
 7592         * usage.footerHeading = Environment Variables:
 7593         * usage.footer.0 = footer line 0
 7594         * usage.footer.1 = footer line 1
 7595         * </pre>
 7596         * @see Command#resourceBundle()
 7597         * @see Option#descriptionKey()
 7598         * @see OptionSpec#description()
 7599         * @see PositionalParamSpec#description()
 7600         * @see CommandSpec#qualifiedName(String)
 7601         * @since 3.6 */
 7602        public static class Messages {
 7603            private final CommandSpec spec;
 7604            private final String bundleBaseName;
 7605            private final ResourceBundle rb;
 7606            private final Set<String> keys;
 7607            public Messages(CommandSpec spec, String baseName) {
 7608                this(spec, baseName, createBundle(baseName));
 7609            }
 7610            public Messages(CommandSpec spec, ResourceBundle rb) {
 7611                this(spec, extractName(rb), rb);
 7612            }
 7613            public Messages(CommandSpec spec, String baseName, ResourceBundle rb) {
 7614                this.spec = Assert.notNull(spec, "CommandSpec");
 7615                this.bundleBaseName = baseName;
 7616                this.rb = rb;
 7617                this.keys = keys(rb);
 7618            }
 7619            private static ResourceBundle createBundle(String baseName) {
 7620                return ResourceBundle.getBundle(baseName);
 7621            }
 7622            private static String extractName(ResourceBundle rb) {
 7623                try { // ResourceBundle.getBaseBundleName was introduced in Java 8
 7624                    return (String) ResourceBundle.class.getDeclaredMethod("getBaseBundleName").invoke(rb);
 7625                } catch (Exception ignored) { return ""; }
 7626            }
 7627            private static Set<String> keys(ResourceBundle rb) {
 7628                if (rb == null) { return Collections.emptySet(); }
 7629                Set<String> keys = new LinkedHashSet<String>();
 7630                for (Enumeration<String> k = rb.getKeys(); k.hasMoreElements(); keys.add(k.nextElement()));
 7631                return keys;
 7632            }
 7633
 7634            /** Returns a copy of the specified Messages object with the CommandSpec replaced by the specified one.
 7635             * @param spec the CommandSpec of the returned Messages
 7636             * @param original the Messages object whose ResourceBundle to reference
 7637             * @return a Messages object with the specified CommandSpec and the ResourceBundle of the specified Messages object
 7638             */
 7639            public static Messages copy(CommandSpec spec, Messages original) {
 7640                return original == null ? null : new Messages(spec, original.bundleBaseName, original.rb);
 7641            }
 7642            /** Returns {@code true} if the specified {@code Messages} is {@code null} or has a {@code null ResourceBundle}. */
 7643            public static boolean empty(Messages messages) { return messages == null || messages.rb == null; }
 7644
 7645            /** Returns the String value found in the resource bundle for the specified key, or the specified default value if not found.
 7646             * @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,
 7647             *             and if not found, it will try with the unqualified key.
 7648             * @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
 7649             * @return the String value found in the resource bundle for the specified key, or the specified default value
 7650             */
 7651            public String getString(String key, String defaultValue) {
 7652                if (isEmpty()) { return defaultValue; }
 7653                String cmd = spec.qualifiedName(".");
 7654                if (keys.contains(cmd + "." + key)) { return rb.getString(cmd + "." + key); }
 7655                if (keys.contains(key)) { return rb.getString(key); }
 7656                return defaultValue;
 7657            }
 7658
 7659            boolean isEmpty() { return rb == null || keys.isEmpty(); }
 7660
 7661            /** Returns the String array value found in the resource bundle for the specified key, or the specified default value if not found.
 7662             * Multi-line strings can be specified in the resource bundle with {@code key.0}, {@code key.1}, {@code key.2}, etc.
 7663             * @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,
 7664             *            and if not found, it will try with the unqualified key.
 7665             * @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
 7666             * @return the String array value found in the resource bundle for the specified key, or the specified default value
 7667             */
 7668            public String[] getStringArray(String key, String[] defaultValues) {
 7669                if (isEmpty()) { return defaultValues; }
 7670                String cmd = spec.qualifiedName(".");
 7671                List<String> result = addAllWithPrefix(rb, cmd + "." + key, keys, new ArrayList<String>());
 7672                if (!result.isEmpty()) { return result.toArray(new String[0]); }
 7673                addAllWithPrefix(rb, key, keys, result);
 7674                return result.isEmpty() ? defaultValues : result.toArray(new String[0]);
 7675            }
 7676            private static List<String> addAllWithPrefix(ResourceBundle rb, String key, Set<String> keys, List<String> result) {
 7677                if (keys.contains(key)) { result.add(rb.getString(key)); }
 7678                for (int i = 0; true; i++) {
 7679                    String elementKey = key + "." + i;
 7680                    if (keys.contains(elementKey)) {
 7681                        result.add(rb.getString(elementKey));
 7682                    } else {
 7683                        return result;
 7684                    }
 7685                }
 7686            }
 7687            /** Returns the ResourceBundle of the specified Messages object or {@code null} if the specified Messages object is {@code null}.
 7688             * @since 4.0 */
 7689            public static String resourceBundleBaseName(Messages messages) { return messages == null ? null : messages.resourceBundleBaseName(); }
 7690            /** Returns the ResourceBundle of the specified Messages object or {@code null} if the specified Messages object is {@code null}. */
 7691            public static ResourceBundle resourceBundle(Messages messages) { return messages == null ? null : messages.resourceBundle(); }
 7692            /** Returns the base name of the ResourceBundle of this object or {@code null}.
 7693             * @since 4.0 */
 7694            public String resourceBundleBaseName() { return bundleBaseName; }
 7695            /** Returns the ResourceBundle of this object or {@code null}. */
 7696            public ResourceBundle resourceBundle() { return rb; }
 7697            /** Returns the CommandSpec of this object, never {@code null}. */
 7698            public CommandSpec commandSpec() { return spec; }
 7699        }
 7700        private static class CommandReflection {
 7701            static ArgGroupSpec extractArgGroupSpec(IAnnotatedElement member, IFactory factory, CommandSpec commandSpec, boolean annotationsAreMandatory) throws Exception {
 7702                Object instance = null;
 7703                try { instance = member.getter().get(); } catch (Exception ignored) {}
 7704                Class<?> cls = instance == null ? member.getTypeInfo().getType() : instance.getClass();
 7705                Tracer t = new Tracer();
 7706
 7707                if (member.isMultiValue()) {
 7708                    cls = member.getTypeInfo().getAuxiliaryTypes()[0];
 7709                }
 7710                IScope scope = new ObjectScope(instance);
 7711                ArgGroupSpec.Builder builder = ArgGroupSpec.builder(member);
 7712                builder.updateArgGroupAttributes(member.getAnnotation(ArgGroup.class));
 7713                if (member.isOption() || member.isParameter()) {
 7714                    if (member instanceof TypedMember) { validateArgSpecMember((TypedMember) member); }
 7715                    builder.addArg(buildArgForMember(member, factory));
 7716                }
 7717
 7718                Stack<Class<?>> hierarchy = new Stack<Class<?>>();
 7719                while (cls != null) { hierarchy.add(cls); cls = cls.getSuperclass(); }
 7720                boolean hasArgAnnotation = false;
 7721                while (!hierarchy.isEmpty()) {
 7722                    cls = hierarchy.pop();
 7723                    hasArgAnnotation |= initFromAnnotatedFields(scope, cls, commandSpec, builder, factory);
 7724                }
 7725                ArgGroupSpec result = builder.build();
 7726                if (annotationsAreMandatory) {validateArgGroupSpec(result, hasArgAnnotation, cls.getName()); }
 7727                return result;
 7728            }
 7729            static CommandSpec extractCommandSpec(Object command, IFactory factory, boolean annotationsAreMandatory) {
 7730                Class<?> cls = command.getClass();
 7731                Tracer t = new Tracer();
 7732                t.debug("Creating CommandSpec for object of class %s with factory %s%n", cls.getName(), factory.getClass().getName());
 7733                if (command instanceof CommandSpec) { return (CommandSpec) command; }
 7734
 7735                Object[] tmp = getOrCreateInstance(cls, command, factory, t);
 7736                cls = (Class<?>) tmp[0];
 7737                Object instance = tmp[1];
 7738                String commandClassName = (String) tmp[2];
 7739
 7740                CommandSpec result = CommandSpec.wrapWithoutInspection(Assert.notNull(instance, "command"));
 7741                ObjectScope scope = new ObjectScope(instance);
 7742
 7743                Stack<Class<?>> hierarchy = new Stack<Class<?>>();
 7744                while (cls != null) { hierarchy.add(cls); cls = cls.getSuperclass(); }
 7745                boolean hasCommandAnnotation = false;
 7746                boolean mixinStandardHelpOptions = false;
 7747                while (!hierarchy.isEmpty()) {
 7748                    cls = hierarchy.pop();
 7749                    Command cmd = cls.getAnnotation(Command.class);
 7750                    if (cmd != null) {
 7751                        result.updateCommandAttributes(cmd, factory);
 7752                        initSubcommands(cmd, cls, result, factory);
 7753                        // addGroups(cmd, groupBuilders); // TODO delete
 7754                        hasCommandAnnotation = true;
 7755                    }
 7756                    hasCommandAnnotation |= initFromAnnotatedFields(scope, cls, result, null, factory);
 7757                    if (cls.isAnnotationPresent(Command.class)) {
 7758                        mixinStandardHelpOptions |= cls.getAnnotation(Command.class).mixinStandardHelpOptions();
 7759                    }
 7760                }
 7761                result.mixinStandardHelpOptions(mixinStandardHelpOptions); //#377 Standard help options should be added last
 7762                if (command instanceof Method) {
 7763                    Method method = (Method) command;
 7764                    t.debug("Using method %s as command %n", method);
 7765                    commandClassName = method.toString();
 7766                    Command cmd = method.getAnnotation(Command.class);
 7767                    result.updateCommandAttributes(cmd, factory);
 7768                    result.setAddMethodSubcommands(false); // method commands don't have method subcommands
 7769                    initSubcommands(cmd, null, result, factory);
 7770                    hasCommandAnnotation = true;
 7771                    result.mixinStandardHelpOptions(method.getAnnotation(Command.class).mixinStandardHelpOptions());
 7772                    initFromMethodParameters(scope, method, result, null, factory);
 7773                    // set command name to method name, unless @Command#name is set
 7774                    result.initName(((Method)command).getName());
 7775                }
 7776                result.updateArgSpecMessages();
 7777
 7778                if (annotationsAreMandatory) {validateCommandSpec(result, hasCommandAnnotation, commandClassName); }
 7779                result.withToString(commandClassName).validate();
 7780                return result;
 7781            }
 7782
 7783            private static Object[] getOrCreateInstance(Class<?> cls, Object command, IFactory factory, Tracer t) {
 7784                Object instance = command;
 7785                String commandClassName = cls.getName();
 7786                if (command instanceof Class) {
 7787                    cls = (Class) command;
 7788                    commandClassName = cls.getName();
 7789                    try {
 7790                        t.debug("Getting a %s instance from the factory%n", cls.getName());
 7791                        instance = DefaultFactory.create(factory, cls);
 7792                        cls = instance.getClass();
 7793                        commandClassName = cls.getName();
 7794                        t.debug("Factory returned a %s instance%n", commandClassName);
 7795                    } catch (InitializationException ex) {
 7796                        if (cls.isInterface()) {
 7797                            t.debug("%s. Creating Proxy for interface %s%n", ex.getCause(), cls.getName());
 7798                            instance = Proxy.newProxyInstance(cls.getClassLoader(), new Class<?>[]{cls}, new PicocliInvocationHandler());
 7799                        } else {
 7800                            throw ex;
 7801                        }
 7802                    }
 7803                } else if (command instanceof Method) {
 7804                    cls = null; // don't mix in options/positional params from outer class @Command
 7805                } else if (instance == null) {
 7806                    t.debug("Getting a %s instance from the factory%n", cls.getName());
 7807                    instance = DefaultFactory.create(factory, cls);
 7808                    t.debug("Factory returned a %s instance%n", instance.getClass().getName());
 7809                }
 7810                return new Object[] { cls, instance, commandClassName };
 7811            }
 7812            private static void initSubcommands(Command cmd, Class<?> cls, CommandSpec parent, IFactory factory) {
 7813                for (Class<?> sub : cmd.subcommands()) {
 7814                    try {
 7815                        if (Help.class == sub) { throw new InitializationException(Help.class.getName() + " is not a valid subcommand. Did you mean " + HelpCommand.class.getName() + "?"); }
 7816                        CommandLine subcommandLine = toCommandLine(factory.create(sub), factory);
 7817                        parent.addSubcommand(subcommandName(sub), subcommandLine);
 7818                        initParentCommand(subcommandLine.getCommandSpec().userObject(), parent.userObject());
 7819                    }
 7820                    catch (InitializationException ex) { throw ex; }
 7821                    catch (NoSuchMethodException ex) { throw new InitializationException("Cannot instantiate subcommand " +
 7822                            sub.getName() + ": the class has no constructor", ex); }
 7823                    catch (Exception ex) {
 7824                        throw new InitializationException("Could not instantiate and add subcommand " +
 7825                                sub.getName() + ": " + ex, ex);
 7826                    }
 7827                }
 7828                if (cmd.addMethodSubcommands() && cls != null) {
 7829                    for (CommandLine sub : CommandSpec.createMethodSubcommands(cls, factory)) {
 7830                        parent.addSubcommand(sub.getCommandName(), sub);
 7831                    }
 7832                }
 7833            }
 7834            static void initParentCommand(Object subcommand, Object parent) {
 7835                if (subcommand == null) { return; }
 7836                try {
 7837                    Class<?> cls = subcommand.getClass();
 7838                    while (cls != null) {
 7839                        for (Field f : cls.getDeclaredFields()) {
 7840                            if (f.isAnnotationPresent(ParentCommand.class)) {
 7841                                f.setAccessible(true);
 7842                                f.set(subcommand, parent);
 7843                            }
 7844                        }
 7845                        cls = cls.getSuperclass();
 7846                    }
 7847                } catch (Exception ex) {
 7848                    throw new InitializationException("Unable to initialize @ParentCommand field: " + ex, ex);
 7849                }
 7850            }
 7851            private static String subcommandName(Class<?> sub) {
 7852                Command subCommand = sub.getAnnotation(Command.class);
 7853                if (subCommand == null || Help.DEFAULT_COMMAND_NAME.equals(subCommand.name())) {
 7854                    throw new InitializationException("Subcommand " + sub.getName() +
 7855                            " is missing the mandatory @Command annotation with a 'name' attribute");
 7856                }
 7857                return subCommand.name();
 7858            }
 7859            private static boolean initFromAnnotatedFields(IScope scope, Class<?> cls, CommandSpec receiver, ArgGroupSpec.Builder groupBuilder, IFactory factory) {
 7860                boolean result = false;
 7861                for (Field field : cls.getDeclaredFields()) {
 7862                    result |= initFromAnnotatedTypedMembers(TypedMember.createIfAnnotated(field, scope), receiver, groupBuilder, factory);
 7863                }
 7864                for (Method method : cls.getDeclaredMethods()) {
 7865                    result |= initFromAnnotatedTypedMembers(TypedMember.createIfAnnotated(method, scope, receiver), receiver, groupBuilder, factory);
 7866                }
 7867                return result;
 7868            }
 7869            @SuppressWarnings("unchecked")
 7870            private static boolean initFromAnnotatedTypedMembers(TypedMember member,
 7871                                                                 CommandSpec commandSpec,
 7872                                                                 ArgGroupSpec.Builder groupBuilder,
 7873                                                                 IFactory factory) {
 7874                boolean result = false;
 7875                if (member == null) { return result; }
 7876                if (member.isMixin()) {
 7877                    assertNoDuplicateAnnotations(member, Mixin.class, Option.class, Parameters.class, Unmatched.class, Spec.class, ArgGroup.class);
 7878                    if (groupBuilder != null) {
 7879                        throw new InitializationException("@Mixins are not supported on @ArgGroups");
 7880                        // TODO groupBuilder.addMixin(member.getMixinName(), buildMixinForMember(member, factory));
 7881                    } else {
 7882                        commandSpec.addMixin(member.getMixinName(), buildMixinForMember(member, factory));
 7883                    }
 7884                    result = true;
 7885                }
 7886                if (member.isArgGroup()) {
 7887                    assertNoDuplicateAnnotations(member, ArgGroup.class, Spec.class, Parameters.class, Option.class, Unmatched.class, Mixin.class);
 7888                    if (groupBuilder != null) {
 7889                        groupBuilder.addSubgroup(buildArgGroupForMember(member, factory, commandSpec));
 7890                    } else {
 7891                        commandSpec.addArgGroup(buildArgGroupForMember(member, factory, commandSpec));
 7892                    }
 7893                    return true;
 7894                }
 7895                if (member.isUnmatched()) {
 7896                    assertNoDuplicateAnnotations(member, Unmatched.class, Mixin.class, Option.class, Parameters.class, Spec.class, ArgGroup.class);
 7897                    if (groupBuilder != null) {
 7898                        // we don't support @Unmatched on @ArgGroup class members...
 7899                        throw new InitializationException("@Unmatched are not supported on @ArgGroups");
 7900                    } else {
 7901                        commandSpec.addUnmatchedArgsBinding(buildUnmatchedForMember(member));
 7902                    }
 7903                }
 7904                if (member.isArgSpec()) {
 7905                    validateArgSpecMember(member);
 7906                    if (groupBuilder != null) {
 7907                        groupBuilder.addArg(buildArgForMember(member, factory));
 7908                    } else {
 7909                        commandSpec.add(buildArgForMember(member, factory));
 7910                    }
 7911                    result = true;
 7912                }
 7913                if (member.isInjectSpec()) {
 7914                    validateInjectSpec(member);
 7915                    try { member.setter().set(commandSpec); } catch (Exception ex) { throw new InitializationException("Could not inject spec", ex); }
 7916                }
 7917                return result;
 7918            }
 7919            private static boolean initFromMethodParameters(IScope scope, Method method, CommandSpec receiver, ArgGroupSpec.Builder groupBuilder, IFactory factory) {
 7920                boolean result = false;
 7921                int optionCount = 0;
 7922                for (int i = 0, count = method.getParameterTypes().length; i < count; i++) {
 7923                    MethodParam param = new MethodParam(method, i);
 7924                    if (param.isAnnotationPresent(Option.class) || param.isAnnotationPresent(Mixin.class)) {
 7925                        optionCount++;
 7926                    } else {
 7927                        param.position = i - optionCount;
 7928                    }
 7929                    result |= initFromAnnotatedTypedMembers(new TypedMember(param, scope), receiver, groupBuilder, factory);
 7930                }
 7931                return result;
 7932            }
 7933            @SuppressWarnings("unchecked")
 7934            private static void validateArgSpecMember(TypedMember member) {
 7935                if (!member.isArgSpec()) { throw new IllegalStateException("Bug: validateArgSpecMember() should only be called with an @Option or @Parameters member"); }
 7936                if (member.isOption()) {
 7937                    assertNoDuplicateAnnotations(member, Option.class, Unmatched.class, Mixin.class, Parameters.class, Spec.class, ArgGroup.class);
 7938                } else {
 7939                    assertNoDuplicateAnnotations(member, Parameters.class, Option.class, Unmatched.class, Mixin.class, Spec.class, ArgGroup.class);
 7940                }
 7941                if (!(member.accessible instanceof Field)) { return; }
 7942                Field field = (Field) member.accessible;
 7943                if (Modifier.isFinal(field.getModifiers()) && (field.getType().isPrimitive() || String.class.isAssignableFrom(field.getType()))) {
 7944                    throw new InitializationException("Constant (final) primitive and String fields like " + field + " cannot be used as " +
 7945                            (member.isOption() ? "an @Option" : "a @Parameter") + ": compile-time constant inlining may hide new values written to it.");
 7946                }
 7947            }
 7948            private static void validateCommandSpec(CommandSpec result, boolean hasCommandAnnotation, String commandClassName) {
 7949                if (!hasCommandAnnotation && result.positionalParameters.isEmpty() && result.optionsByNameMap.isEmpty() && result.unmatchedArgs.isEmpty()) {
 7950                    throw new InitializationException(commandClassName + " is not a command: it has no @Command, @Option, @Parameters or @Unmatched annotations");
 7951                }
 7952            }
 7953            private static void validateArgGroupSpec(ArgGroupSpec result, boolean hasArgAnnotation, String className) {
 7954                if (!hasArgAnnotation && result.args().isEmpty()) {
 7955                    throw new InitializationException(className + " is not a group: it has no @Option or @Parameters annotations");
 7956                }
 7957            }
 7958            @SuppressWarnings("unchecked")
 7959            private static void validateInjectSpec(TypedMember member) {
 7960                if (!member.isInjectSpec()) { throw new IllegalStateException("Bug: validateInjectSpec() should only be called with @Spec members"); }
 7961                assertNoDuplicateAnnotations(member, Spec.class, Parameters.class, Option.class, Unmatched.class, Mixin.class, ArgGroup.class);
 7962                if (!CommandSpec.class.getName().equals(member.getTypeInfo().getClassName())) {
 7963                    throw new InitializationException("@picocli.CommandLine.Spec annotation is only supported on fields of type " + CommandSpec.class.getName());
 7964                }
 7965            }
 7966            private static void assertNoDuplicateAnnotations(TypedMember member, Class<? extends Annotation> myAnnotation, Class<? extends Annotation>... forbidden) {
 7967                for (Class<? extends Annotation> annotation : forbidden) {
 7968                    if (member.isAnnotationPresent(annotation)) {
 7969                        throw new DuplicateOptionAnnotationsException("A member cannot have both @" + myAnnotation.getSimpleName() + " and @" + annotation.getSimpleName() + " annotations, but '" + member + "' has both.");
 7970                    }
 7971                }
 7972            }
 7973            private static CommandSpec buildMixinForMember(IAnnotatedElement member, IFactory factory) {
 7974                try {
 7975                    Object userObject = member.getter().get();
 7976                    if (userObject == null) {
 7977                        userObject = factory.create(member.getTypeInfo().getType());
 7978                        member.setter().set(userObject);
 7979                    }
 7980                    CommandSpec result = CommandSpec.forAnnotatedObject(userObject, factory);
 7981                    return result.withToString(member.getToString());
 7982                } catch (InitializationException ex) {
 7983                    throw ex;
 7984                } catch (Exception ex) {
 7985                    throw new InitializationException("Could not access or modify mixin member " + member + ": " + ex, ex);
 7986                }
 7987            }
 7988            private static ArgSpec buildArgForMember(IAnnotatedElement member, IFactory factory) {
 7989                if (member.isOption())         { return OptionSpec.builder(member, factory).build(); }
 7990                else if (member.isParameter()) { return PositionalParamSpec.builder(member, factory).build(); }
 7991                else                           { return PositionalParamSpec.builder(member, factory).build(); }
 7992            }
 7993            private static ArgGroupSpec buildArgGroupForMember(IAnnotatedElement member, IFactory factory, CommandSpec commandSpec) {
 7994                try {
 7995                    return extractArgGroupSpec(member, factory, commandSpec, true);
 7996                } catch (InitializationException ex) {
 7997                    throw ex;
 7998                } catch (Exception ex) {
 7999                    throw new InitializationException("Could not access or modify ArgGroup member " + member + ": " + ex, ex);
 8000                }
 8001            }
 8002            private static UnmatchedArgsBinding buildUnmatchedForMember(final IAnnotatedElement member) {
 8003                ITypeInfo info = member.getTypeInfo();
 8004                if (!(info.getClassName().equals(String[].class.getName()) ||
 8005                        (info.isCollection() && info.getActualGenericTypeArguments().equals(Arrays.asList(String.class.getName()))))) {
 8006                    throw new InitializationException("Invalid type for " + member + ": must be either String[] or List<String>");
 8007                }
 8008                if (info.getClassName().equals(String[].class.getName())) {
 8009                    return UnmatchedArgsBinding.forStringArrayConsumer(member.setter());
 8010                } else {
 8011                    return UnmatchedArgsBinding.forStringCollectionSupplier(new IGetter() {
 8012                        @SuppressWarnings("unchecked") public <T> T get() throws Exception {
 8013                            List<String> result = (List<String>) member.getter().get();
 8014                            if (result == null) {
 8015                                result = new ArrayList<String>();
 8016                                member.setter().set(result);
 8017                            }
 8018                            return (T) result;
 8019                        }
 8020                    });
 8021                }
 8022            }
 8023        }
 8024
 8025        static class FieldBinding implements IGetter, ISetter {
 8026            private final IScope scope;
 8027            private final Field field;
 8028            private static IScope asScope(Object scope) { return scope instanceof IScope ? ((IScope) scope) : new ObjectScope(scope); }
 8029            FieldBinding(Object scope, Field field) { this(asScope(scope), field); }
 8030            FieldBinding(IScope scope, Field field) { this.scope = scope; this.field = field; }
 8031            public <T> T get() throws PicocliException {
 8032                Object obj = null;
 8033                try { obj = scope.get(); }
 8034                catch (Exception ex) { throw new PicocliException("Could not get scope for field " + field, ex); }
 8035                try {
 8036                    @SuppressWarnings("unchecked") T result = (T) field.get(obj);
 8037                    return result;
 8038                } catch (Exception ex) {
 8039                    throw new PicocliException("Could not get value for field " + field, ex);
 8040                }
 8041            }
 8042            public <T> T set(T value) throws PicocliException {
 8043                Object obj = null;
 8044                try { obj = scope.get(); }
 8045                catch (Exception ex) { throw new PicocliException("Could not get scope for field " + field, ex); }
 8046                try {
 8047                    @SuppressWarnings("unchecked") T result = (T) field.get(obj);
 8048                    field.set(obj, value);
 8049                    return result;
 8050                } catch (Exception ex) {
 8051                    throw new PicocliException("Could not set value for field " + field + " to " + value, ex);
 8052                }
 8053            }
 8054            public String toString() {
 8055                return String.format("%s(%s %s.%s)", getClass().getSimpleName(), field.getType().getName(),
 8056                        field.getDeclaringClass().getName(), field.getName());
 8057            }
 8058        }
 8059        static class MethodBinding implements IGetter, ISetter {
 8060            private final IScope scope;
 8061            private final Method method;
 8062            private final CommandSpec spec;
 8063            private Object currentValue;
 8064            MethodBinding(IScope scope, Method method, CommandSpec spec) {
 8065                this.scope = scope;
 8066                this.method = method;
 8067                this.spec = spec;
 8068            }
 8069            @SuppressWarnings("unchecked") public <T> T get() { return (T) currentValue; }
 8070            public <T> T set(T value) throws PicocliException {
 8071                Object obj = null;
 8072                try { obj = scope.get(); }
 8073                catch (Exception ex) { throw new PicocliException("Could not get scope for method " + method, ex); }
 8074                try {
 8075                    @SuppressWarnings("unchecked") T result = (T) currentValue;
 8076                    method.invoke(obj, value);
 8077                    currentValue = value;
 8078                    return result;
 8079                } catch (InvocationTargetException ex) {
 8080                    if (ex.getCause() instanceof PicocliException) { throw (PicocliException) ex.getCause(); }
 8081                    throw createParameterException(value, ex.getCause());
 8082                } catch (Exception ex) {
 8083                    throw createParameterException(value, ex);
 8084                }
 8085            }
 8086            private ParameterException createParameterException(Object value, Throwable t) {
 8087                CommandLine cmd = spec.commandLine() == null ? new CommandLine(spec) : spec.commandLine();
 8088                return new ParameterException(cmd, "Could not invoke " + method + " with " + value, t);
 8089            }
 8090            public String toString() {
 8091                return String.format("%s(%s)", getClass().getSimpleName(), method);
 8092            }
 8093        }
 8094        private static class PicocliInvocationHandler implements InvocationHandler {
 8095            final Map<String, Object> map = new HashMap<String, Object>();
 8096            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 8097                return map.get(method.getName());
 8098            }
 8099            class ProxyBinding implements IGetter, ISetter {
 8100                private final Method method;
 8101                ProxyBinding(Method method) { this.method = Assert.notNull(method, "method"); }
 8102                @SuppressWarnings("unchecked") public <T> T get() { return (T) map.get(method.getName()); }
 8103                public <T> T set(T value) {
 8104                    T result = get();
 8105                    map.put(method.getName(), value);
 8106                    return result;
 8107                }
 8108            }
 8109        }
 8110        private static class ObjectBinding implements IGetter, ISetter {
 8111            private Object value;
 8112            @SuppressWarnings("unchecked") public <T> T get() { return (T) value; }
 8113            public <T> T set(T value) {
 8114                @SuppressWarnings("unchecked") T result = value;
 8115                this.value = value;
 8116                return result;
 8117            }
 8118            public String toString() {
 8119                return String.format("%s(value=%s)", getClass().getSimpleName(), value);
 8120            }
 8121        }
 8122        static class ObjectScope implements IScope {
 8123            private Object value;
 8124            public ObjectScope(Object value) { this.value = value; }
 8125            @SuppressWarnings("unchecked") public <T> T get() { return (T) value; }
 8126            @SuppressWarnings("unchecked") public <T> T set(T value) { T old = (T) this.value; this.value = value; return old; }
 8127            public static Object tryGet(IScope scope) {
 8128                try {
 8129                    return scope.get();
 8130                } catch (Exception e) {
 8131                    throw new InitializationException("Could not get scope value", e);
 8132                }
 8133            }
 8134            public String toString() { return String.format("Scope(value=%s)", value); }
 8135        }
 8136    }
 8137
 8138    /** Encapsulates the result of parsing an array of command line arguments.
 8139     * @since 3.0 */
 8140    public static class ParseResult {
 8141        private final CommandSpec commandSpec;
 8142        private final List<OptionSpec> matchedOptions;
 8143        private final List<PositionalParamSpec> matchedUniquePositionals;
 8144        private final List<String> originalArgs;
 8145        private final List<String> unmatched;
 8146        private final List<List<PositionalParamSpec>> matchedPositionalParams;
 8147        private final List<Exception> errors;
 8148        private final MatchedGroup matchedGroup;
 8149        final List<Object> tentativeMatch;
 8150
 8151        private final ParseResult subcommand;
 8152        private final boolean usageHelpRequested;
 8153        private final boolean versionHelpRequested;
 8154
 8155        private ParseResult(ParseResult.Builder builder) {
 8156            commandSpec = builder.commandSpec;
 8157            subcommand = builder.subcommand;
 8158            matchedOptions = new ArrayList<OptionSpec>(builder.options);
 8159            unmatched = new ArrayList<String>(builder.unmatched);
 8160            originalArgs = new ArrayList<String>(builder.originalArgList);
 8161            matchedUniquePositionals = new ArrayList<PositionalParamSpec>(builder.positionals);
 8162            matchedPositionalParams = new ArrayList<List<PositionalParamSpec>>(builder.positionalParams);
 8163            errors = new ArrayList<Exception>(builder.errors);
 8164            usageHelpRequested = builder.usageHelpRequested;
 8165            versionHelpRequested = builder.versionHelpRequested;
 8166            tentativeMatch = builder.nowProcessing;
 8167            matchedGroup = builder.matchedGroup.trim();
 8168        }
 8169        /** Creates and returns a new {@code ParseResult.Builder} for the specified command spec. */
 8170        public static Builder builder(CommandSpec commandSpec) { return new Builder(commandSpec); }
 8171
 8172        /**
 8173         * Returns the matches for the specified argument group.
 8174         * @since 4.0 */
 8175        public List<MatchedGroup> findMatchedGroup(ArgGroupSpec group) {
 8176            return matchedGroup.findMatchedGroup(group, new ArrayList<MatchedGroup>());
 8177        }
 8178
 8179        /**
 8180         * Returns the top-level container for the {@link ArgGroupSpec ArgGroupSpec} match or matches found.
 8181         * <p>
 8182         * If the user input was a valid combination of group arguments, the returned list should contain a single
 8183         * {@linkplain MatchedGroupMultiple multiple}. Details of the {@linkplain MatchedGroup matched groups} encountered
 8184         * on the command line can be obtained via its {@link MatchedGroupMultiple#matchedSubgroups() matchedSubgroups()} method.
 8185         * The top-level multiple returned by this method contains no {@linkplain MatchedGroupMultiple#matchedValues(ArgSpec) matched arguments}.
 8186         * </p><p>
 8187         * If the returned list contains more than one {@linkplain MatchedGroupMultiple multiple}, the user input was invalid:
 8188         * the maximum {@linkplain ArgGroup#multiplicity() multiplicity} of a group was exceeded, and the parser created an extra
 8189         * {@code multiple} to capture the values. Usually this results in a {@link ParameterException ParameterException}
 8190         * being thrown by the {@code parse} method, unless the parser is configured to {@linkplain ParserSpec#collectErrors() collect errors}.
 8191         * </p>
 8192         * @since 4.0 */
 8193        public List<MatchedGroupMultiple> getMatchedGroupMultiples() {
 8194            return matchedGroup.multiples();
 8195        }
 8196        /** Returns the option with the specified short name, or {@code null} if no option with that name was matched
 8197         * on the command line.
 8198         * <p>Use {@link OptionSpec#getValue() getValue} on the returned {@code OptionSpec} to get the matched value (or values),
 8199         * converted to the type of the option. Alternatively, use {@link OptionSpec#stringValues() stringValues}
 8200         * to get the matched String values after they were {@linkplain OptionSpec#splitRegex() split} into parts, or
 8201         * {@link OptionSpec#originalStringValues() originalStringValues} to get the original String values that were
 8202         * matched on the command line, before any processing.
 8203         * </p><p>To get the {@linkplain OptionSpec#defaultValue() default value} of an option that was
 8204         * {@linkplain #hasMatchedOption(char) <em>not</em> matched} on the command line, use
 8205         * {@code parseResult.commandSpec().findOption(shortName).getValue()}. </p>
 8206         * @see CommandSpec#findOption(char)  */
 8207        public OptionSpec matchedOption(char shortName) { return CommandSpec.findOption(shortName, matchedOptions); }
 8208
 8209        /** Returns the option with the specified name, or {@code null} if no option with that name was matched on the command line.
 8210         * <p>Use {@link OptionSpec#getValue() getValue} on the returned {@code OptionSpec} to get the matched value (or values),
 8211         * converted to the type of the option. Alternatively, use {@link OptionSpec#stringValues() stringValues}
 8212         * to get the matched String values after they were {@linkplain OptionSpec#splitRegex() split} into parts, or
 8213         * {@link OptionSpec#originalStringValues() originalStringValues} to get the original String values that were
 8214         * matched on the command line, before any processing.
 8215         * </p><p>To get the {@linkplain OptionSpec#defaultValue() default value} of an option that was
 8216         * {@linkplain #hasMatchedOption(String) <em>not</em> matched} on the command line, use
 8217         * {@code parseResult.commandSpec().findOption(String).getValue()}. </p>
 8218         * @see CommandSpec#findOption(String)
 8219         * @param name used to search the matched options. May be an alias of the option name that was actually specified on the command line.
 8220         *      The specified name may include option name prefix characters or not. */
 8221        public OptionSpec matchedOption(String name) { return CommandSpec.findOption(name, matchedOptions); }
 8222
 8223        /** 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. */
 8224        public PositionalParamSpec matchedPositional(int position) {
 8225            if (matchedPositionalParams.size() <= position || matchedPositionalParams.get(position).isEmpty()) { return null; }
 8226            return matchedPositionalParams.get(position).get(0);
 8227        }
 8228
 8229        /** 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. */
 8230        public List<PositionalParamSpec> matchedPositionals(int position) {
 8231            if (matchedPositionalParams.size() <= position) { return Collections.emptyList(); }
 8232            return matchedPositionalParams.get(position) == null ? Collections.<PositionalParamSpec>emptyList() : matchedPositionalParams.get(position);
 8233        }
 8234        /** Returns the {@code CommandSpec} for the matched command. */
 8235        public CommandSpec commandSpec()                    { return commandSpec; }
 8236
 8237        /** Returns whether an option whose aliases include the specified short name was matched on the command line.
 8238         * @param shortName used to search the matched options. May be an alias of the option name that was actually specified on the command line. */
 8239        public boolean hasMatchedOption(char shortName)     { return matchedOption(shortName) != null; }
 8240        /** Returns whether an option whose aliases include the specified name was matched on the command line.
 8241         * @param name used to search the matched options. May be an alias of the option name that was actually specified on the command line.
 8242         *      The specified name may include option name prefix characters or not. */
 8243        public boolean hasMatchedOption(String name)        { return matchedOption(name) != null; }
 8244        /** Returns whether the specified option was matched on the command line. */
 8245        public boolean hasMatchedOption(OptionSpec option)  { return matchedOptions.contains(option); }
 8246
 8247        /** Returns whether a positional parameter was matched at the specified position. */
 8248        public boolean hasMatchedPositional(int position)   { return matchedPositional(position) != null; }
 8249        /** Returns whether the specified positional parameter was matched on the command line. */
 8250        public boolean hasMatchedPositional(PositionalParamSpec positional) { return matchedUniquePositionals.contains(positional); }
 8251
 8252        /** Returns a list of matched options, in the order they were found on the command line. */
 8253        public List<OptionSpec> matchedOptions()            { return Collections.unmodifiableList(matchedOptions); }
 8254
 8255        /** Returns a list of matched positional parameters. */
 8256        public List<PositionalParamSpec> matchedPositionals() { return Collections.unmodifiableList(matchedUniquePositionals); }
 8257
 8258        /** Returns a list of command line arguments that did not match any options or positional parameters. */
 8259        public List<String> unmatched()                     { return Collections.unmodifiableList(unmatched); }
 8260
 8261        /** Returns the command line arguments that were parsed. */
 8262        public List<String> originalArgs()                  { return Collections.unmodifiableList(originalArgs); }
 8263
 8264        /** If {@link ParserSpec#collectErrors} is {@code true}, returns the list of exceptions that were encountered during parsing, otherwise, returns an empty list.
 8265         * @since 3.2 */
 8266        public List<Exception> errors()                     { return Collections.unmodifiableList(errors); }
 8267
 8268        /** 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. */
 8269        public <T> T matchedOptionValue(char shortName, T defaultValue)    { return matchedOptionValue(matchedOption(shortName), defaultValue); }
 8270        /** 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. */
 8271        public <T> T matchedOptionValue(String name, T defaultValue)       { return matchedOptionValue(matchedOption(name), defaultValue); }
 8272        /** 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}. */
 8273        @SuppressWarnings("unchecked")
 8274        private <T> T matchedOptionValue(OptionSpec option, T defaultValue) { return option == null ? defaultValue : (T) option.getValue(); }
 8275
 8276        /** 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. */
 8277        public <T> T matchedPositionalValue(int position, T defaultValue)  { return matchedPositionalValue(matchedPositional(position), defaultValue); }
 8278        /** 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}. */
 8279        @SuppressWarnings("unchecked")
 8280        private <T> T matchedPositionalValue(PositionalParamSpec positional, T defaultValue) { return positional == null ? defaultValue : (T) positional.getValue(); }
 8281
 8282        /** Returns {@code true} if a subcommand was matched on the command line, {@code false} otherwise. */
 8283        public boolean hasSubcommand()          { return subcommand != null; }
 8284
 8285        /** 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. */
 8286        public ParseResult subcommand()         { return subcommand; }
 8287
 8288        /** Returns {@code true} if one of the options that was matched on the command line is a {@link OptionSpec#usageHelp() usageHelp} option. */
 8289        public boolean isUsageHelpRequested()   { return usageHelpRequested; }
 8290
 8291        /** Returns {@code true} if one of the options that was matched on the command line is a {@link OptionSpec#versionHelp() versionHelp} option. */
 8292        public boolean isVersionHelpRequested() { return versionHelpRequested; }
 8293
 8294        /** Returns this {@code ParseResult} as a list of {@code CommandLine} objects, one for each matched command/subcommand.
 8295         * For backwards compatibility with pre-3.0 methods. */
 8296        public List<CommandLine> asCommandLineList() {
 8297            List<CommandLine> result = new ArrayList<CommandLine>();
 8298            ParseResult pr = this;
 8299            while (pr != null) { result.add(pr.commandSpec().commandLine()); pr = pr.hasSubcommand() ? pr.subcommand() : null; }
 8300            return result;
 8301        }
 8302
 8303        /** Builds immutable {@code ParseResult} instances. */
 8304        public static class Builder {
 8305            private final CommandSpec commandSpec;
 8306            private final Set<OptionSpec> options = new LinkedHashSet<OptionSpec>();
 8307            private final Set<PositionalParamSpec> positionals = new LinkedHashSet<PositionalParamSpec>();
 8308            private final List<String> unmatched = new ArrayList<String>();
 8309            private final List<String> originalArgList = new ArrayList<String>();
 8310            private final List<List<PositionalParamSpec>> positionalParams = new ArrayList<List<PositionalParamSpec>>();
 8311            private ParseResult subcommand;
 8312            private boolean usageHelpRequested;
 8313            private boolean versionHelpRequested;
 8314            boolean isInitializingDefaultValues;
 8315            private List<Exception> errors = new ArrayList<Exception>(1);
 8316            private List<Object> nowProcessing;
 8317            private MatchedGroup matchedGroup = new MatchedGroup(null, null);
 8318
 8319            private Builder(CommandSpec spec) { commandSpec = Assert.notNull(spec, "commandSpec"); }
 8320            /** Creates and returns a new {@code ParseResult} instance for this builder's configuration. */
 8321            public ParseResult build() {
 8322                return new ParseResult(this);
 8323            }
 8324
 8325            private void nowProcessing(ArgSpec spec, Object value) {
 8326                if (nowProcessing != null && !isInitializingDefaultValues) {
 8327                    nowProcessing.add(spec.isPositional() ? spec : value);
 8328                }
 8329            }
 8330
 8331            /** Adds the specified {@code OptionSpec} or {@code PositionalParamSpec} to the list of options and parameters
 8332             * that were matched on the command line.
 8333             * @param arg the matched {@code OptionSpec} or {@code PositionalParamSpec}
 8334             * @param position the command line position at which the  {@code PositionalParamSpec} was matched. Ignored for {@code OptionSpec}s.
 8335             * @return this builder for method chaining */
 8336            public Builder add(ArgSpec arg, int position) {
 8337                if (arg.isOption()) {
 8338                    addOption((OptionSpec) arg);
 8339                } else {
 8340                    addPositionalParam((PositionalParamSpec) arg, position);
 8341                }
 8342                afterMatchingGroupElement(arg, position);
 8343                return this;
 8344            }
 8345
 8346            /** Adds the specified {@code OptionSpec} to the list of options that were matched on the command line. */
 8347            public Builder addOption(OptionSpec option) { if (!isInitializingDefaultValues) {options.add(option);} return this; }
 8348            /** Adds the specified {@code PositionalParamSpec} to the list of parameters that were matched on the command line.
 8349             * @param positionalParam the matched {@code PositionalParamSpec}
 8350             * @param position the command line position at which the  {@code PositionalParamSpec} was matched.
 8351             * @return this builder for method chaining */
 8352            public Builder addPositionalParam(PositionalParamSpec positionalParam, int position) {
 8353                if (isInitializingDefaultValues) { return this; }
 8354                positionals.add(positionalParam);
 8355                while (positionalParams.size() <= position) { positionalParams.add(new ArrayList<PositionalParamSpec>()); }
 8356                positionalParams.get(position).add(positionalParam);
 8357                return this;
 8358            }
 8359            /** Adds the specified command line argument to the list of unmatched command line arguments. */
 8360            public Builder addUnmatched(String arg) { unmatched.add(arg); return this; }
 8361            /** Adds all elements of the specified command line arguments stack to the list of unmatched command line arguments. */
 8362            public Builder addUnmatched(Stack<String> args) { while (!args.isEmpty()) { addUnmatched(args.pop()); } return this; }
 8363            /** Sets the specified {@code ParseResult} for a subcommand that was matched on the command line. */
 8364            public Builder subcommand(ParseResult subcommand) { this.subcommand = subcommand; return this; }
 8365            /** Sets the specified command line arguments that were parsed. */
 8366            public Builder originalArgs(String[] originalArgs) { originalArgList.addAll(Arrays.asList(originalArgs)); return this;}
 8367
 8368            void addStringValue        (ArgSpec argSpec, String value) { if (!isInitializingDefaultValues) { argSpec.stringValues.add(value);} }
 8369            void addOriginalStringValue(ArgSpec argSpec, String value) {
 8370                if (!isInitializingDefaultValues) {
 8371                    argSpec.originalStringValues.add(value);
 8372                    if (argSpec.group() != null) {
 8373                        MatchedGroup matchedGroup = this.matchedGroup.findOrCreateMatchingGroup(argSpec, commandSpec.commandLine);
 8374                        matchedGroup.multiple().addOriginalStringValue(argSpec, value);
 8375                    }
 8376                }
 8377            }
 8378
 8379            void addTypedValues(ArgSpec argSpec, int position, Object typedValue) {
 8380                if (!isInitializingDefaultValues) {
 8381                    argSpec.typedValues.add(typedValue);
 8382                    if (argSpec.group() == null) {
 8383                        argSpec.typedValueAtPosition.put(position, typedValue);
 8384                    } else {
 8385                        MatchedGroup matchedGroup = this.matchedGroup.findOrCreateMatchingGroup(argSpec, commandSpec.commandLine);
 8386                        matchedGroup.multiple().addMatchedValue(argSpec, position, typedValue, commandSpec.commandLine.tracer);
 8387                    }
 8388                }
 8389            }
 8390
 8391            public void addError(PicocliException ex) {
 8392                errors.add(Assert.notNull(ex, "exception"));
 8393            }
 8394
 8395            void beforeMatchingGroupElement(ArgSpec argSpec) throws Exception {
 8396                ArgGroupSpec group = argSpec.group();
 8397                if (group == null || isInitializingDefaultValues) { return; }
 8398                MatchedGroup foundMatchedGroup = this.matchedGroup.findOrCreateMatchingGroup(argSpec, commandSpec.commandLine);
 8399                if (foundMatchedGroup.multiple().matchedMinElements() && argSpec.required()) {
 8400                    // we need to create a new multiple; if maxMultiplicity has been reached, we need to add a new MatchedGroup.
 8401                    String elementDescription = ArgSpec.describe(argSpec, "=");
 8402                    Tracer tracer = commandSpec.commandLine.tracer;
 8403                    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);
 8404                    foundMatchedGroup.addMultiple(commandSpec.commandLine);
 8405                }
 8406            }
 8407
 8408            private void afterMatchingGroupElement(ArgSpec argSpec, int position) {
 8409//                ArgGroupSpec group = argSpec.group();
 8410//                if (group == null || isInitializingDefaultValues) { return; }
 8411//                MatchedGroup matchedGroup = this.matchedGroup.findOrCreateMatchingGroup(argSpec, commandSpec.commandLine);
 8412//                promotePartiallyMatchedGroupToMatched(group, matchedGroup, true);
 8413            }
 8414
 8415            private void promotePartiallyMatchedGroupToMatched(ArgGroupSpec group, MatchedGroup matchedGroup, boolean allRequired) {
 8416                if (!matchedGroup.matchedFully(allRequired)) { return; }
 8417
 8418                // FIXME: before promoting the child group, check to see if the parent is matched, given the child group
 8419
 8420                Tracer tracer = commandSpec.commandLine.tracer;
 8421                if (matchedGroup.matchedMaxElements()) {
 8422                    tracer.info("Marking matched group %s as complete: max elements reached. User object: %s%n", matchedGroup, matchedGroup.group.userObject());
 8423                    matchedGroup.complete(commandSpec.commandLine());
 8424                }
 8425            }
 8426        }
 8427
 8428        /** Provides information about an {@link ArgGroup} that was matched on the command line.
 8429         * <p>
 8430         * The {@code ParseResult} may have more than one {@code MatchedGroup} for an {@code ArgGroupSpec}, when the
 8431         * group was matched more often than its maximum {@linkplain ArgGroup#multiplicity() multiplicity}.
 8432         * This is not necessarily a problem: the parser will add a multiple to the {@linkplain MatchedGroup#parentMatchedGroup() parent matched group}
 8433         * 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.
 8434         * </p><p>
 8435         * Ultimately, as long as the {@link ParseResult#getMatchedGroupMultiples()} method does not return more than one multiple, the maximum number of elements is not exceeded.
 8436         * </p>
 8437         * @since 4.0 */
 8438        public static class MatchedGroup {
 8439            private final ArgGroupSpec group;
 8440            private MatchedGroup parentMatchedGroup;
 8441            private List<MatchedGroupMultiple> multiples = new ArrayList<MatchedGroupMultiple>();
 8442
 8443            MatchedGroup(ArgGroupSpec group, CommandLine cmd) { this.group = group; addMultiple(cmd);}
 8444
 8445            /** Returns the {@code ArgGroupSpec} whose matches are captured in this {@code MatchedGroup}. */
 8446            public ArgGroupSpec group() { return group; }
 8447            /** Returns the {@code MatchedGroup} of the parent {@code ArgGroupSpec}, or {@code null} if this group has no parent. */
 8448            public MatchedGroup parentMatchedGroup() { return parentMatchedGroup; }
 8449            /** Returns the list of {@code MatchedGroupMultiple} instances: {@code ArgGroupSpec}s with a multiplicity greater than one may be matched multiple times. */
 8450            public List<MatchedGroupMultiple> multiples() { return Collections.unmodifiableList(multiples); }
 8451
 8452            void addMultiple(CommandLine commandLine) {
 8453                Tracer tracer = commandLine == null ? new Tracer() : commandLine.tracer;
 8454                if (group != null && isMaxMultiplicityReached()) {
 8455                    tracer.info("Completing MatchedGroup %s: max multiplicity is reached.%n", this);
 8456                    complete(commandLine);
 8457                } else {
 8458                    if (group != null) {
 8459                        tracer.info("Adding multiple to MatchedGroup %s (group=%s %s).%n", this, group == null ? "?" : group.id(), group == null ? "ROOT" : group.synopsis());
 8460                    }
 8461                    multiples.add(new MatchedGroupMultiple(this));
 8462                    if (group == null) { return; }
 8463                }
 8464                group.initUserObject(commandLine);
 8465            }
 8466            void complete(CommandLine commandLine) {
 8467                if (parentMatchedGroup == null) {
 8468                    addMultiple(commandLine); // we have no choice but to potentially exceed the max multiplicity of this group...
 8469                } else {
 8470                    parentMatchedGroup.addMultiple(commandLine);
 8471                }
 8472            }
 8473            /** Returns the "active" multiple of this MatchedGroup. */
 8474            MatchedGroupMultiple multiple()    { return multiples.get(multiples.size() - 1); }
 8475            /** 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.*/
 8476            boolean isMaxMultiplicityReached() { return multiples.size() >= group.multiplicity.max; }
 8477            /** 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. */
 8478            boolean isMinMultiplicityReached() { return multiples.size() >= group.multiplicity.min; }
 8479
 8480            /** Returns {@code true} if the minimum number of multiples has been matched for the multiplicity of this group,
 8481             * and each multiple has matched at least the {@linkplain MatchedGroupMultiple#matchedMinElements() minimum number of elements}.*/
 8482            boolean matchedMinElements() { return matchedFully(false); }
 8483            /** Returns {@code true} if the maximum number of multiples has been matched for the multiplicity of this group,
 8484             * and the last multiple has {@linkplain MatchedGroupMultiple#matchedMaxElements() matched the maximum number of elements},
 8485             * while all other multiples have matched at least the {@linkplain MatchedGroupMultiple#matchedMinElements() minimum number of elements}.*/
 8486            boolean matchedMaxElements() { return matchedFully(true); }
 8487            private boolean matchedFully(boolean allRequired) {
 8488                for (MatchedGroupMultiple multiple : multiples) {
 8489                    boolean actuallyAllRequired = allRequired && multiple == multiple();
 8490                    if (!multiple.matchedFully(actuallyAllRequired)) { return false; }
 8491                }
 8492                return allRequired ? isMaxMultiplicityReached() : isMinMultiplicityReached();
 8493            }
 8494
 8495            private MatchedGroup findOrCreateMatchingGroup(ArgSpec argSpec, CommandLine commandLine) {
 8496                ArgGroupSpec searchGroup = Assert.notNull(argSpec.group(), "group for " + argSpec);
 8497                MatchedGroup match = this;
 8498                if (searchGroup == match.group()) { return match; }
 8499                List<ArgGroupSpec> keys = new ArrayList<ArgGroupSpec>();
 8500                while (searchGroup != null) {
 8501                    keys.add(searchGroup);
 8502                    searchGroup = searchGroup.parentGroup();
 8503                }
 8504                Collections.reverse(keys);
 8505                for (ArgGroupSpec key : keys) {
 8506                    MatchedGroup sub = match.multiple().matchedSubgroups().get(key);
 8507                    if (sub == null) {
 8508                        sub = createMatchedGroup(key, match, commandLine);
 8509                    }
 8510                    match = sub;
 8511                }
 8512                return match;
 8513            }
 8514            private MatchedGroup createMatchedGroup(ArgGroupSpec group, MatchedGroup parent, CommandLine commandLine) {
 8515                MatchedGroup result = new MatchedGroup(group, commandLine);
 8516                result.parentMatchedGroup = parent;
 8517                parent.multiple().matchedSubgroups.put(group, result);
 8518                return result;
 8519            }
 8520            MatchedGroup trim() {
 8521                for (Iterator<MatchedGroupMultiple> iter = multiples.iterator(); iter.hasNext(); ) {
 8522                    MatchedGroupMultiple multiple = iter.next();
 8523                    if (multiple.isEmpty()) { iter.remove(); }
 8524                    for (MatchedGroup sub : multiple.matchedSubgroups.values()) { sub.trim(); }
 8525                }
 8526                return this;
 8527            }
 8528
 8529            List<MatchedGroup> findMatchedGroup(ArgGroupSpec group, List<MatchedGroup> result) {
 8530                if (this.group == group) { result.add(this); return result; }
 8531                for (MatchedGroupMultiple multiple : multiples()) {
 8532                    for (MatchedGroup mg : multiple.matchedSubgroups.values()) {
 8533                        mg.findMatchedGroup(group, result);
 8534                    }
 8535                }
 8536                return result;
 8537            }
 8538
 8539            @Override public String toString() {
 8540                return toString(new StringBuilder()).toString();
 8541            }
 8542
 8543            private StringBuilder toString(StringBuilder result) {
 8544                String prefix = result.length() == 0 ? "={" : "";
 8545                String suffix = result.length() == 0 ? "}" : "";
 8546                if (group != null && result.length() == 0) {
 8547                    result.append(group.synopsis());
 8548                }
 8549                result.append(prefix);
 8550                String infix = "";
 8551                for (MatchedGroupMultiple occurrence : multiples) {
 8552                    result.append(infix);
 8553                    occurrence.toString(result);
 8554                    infix = " ";
 8555                }
 8556                return result.append(suffix);
 8557
 8558            }
 8559        }
 8560
 8561        /** A group's {@linkplain ArgGroup#multiplicity() multiplicity} specifies how many multiples of a group can/must
 8562         * appear on the command line before a group is fully matched. This class models a single "multiple".
 8563         * For example, this group: {@code (-a -b) (-a -b)} requires two multiples of its arguments to fully match.
 8564         * @since 4.0
 8565         */
 8566        public static class MatchedGroupMultiple {
 8567            int position;
 8568            final MatchedGroup container;
 8569
 8570            Map<ArgGroupSpec, MatchedGroup> matchedSubgroups = new LinkedHashMap<ArgGroupSpec, MatchedGroup>(2); // preserve order: used in toString()
 8571            Map<ArgSpec, List<Object>> matchedValues         = new IdentityHashMap<ArgSpec, List<Object>>(); // identity map for performance
 8572            Map<ArgSpec, List<String>> originalStringValues  = new LinkedHashMap<ArgSpec, List<String>>(); // preserve order: used in toString()
 8573            Map<ArgSpec, Map<Integer, List<Object>>> matchedValuesAtPosition = new IdentityHashMap<ArgSpec, Map<Integer, List<Object>>>();
 8574
 8575            MatchedGroupMultiple(MatchedGroup container) { this.container = container; }
 8576
 8577            /** Returns {@code true} if this multiple has no matched arguments and no matched subgroups. */
 8578            public boolean isEmpty() { return originalStringValues.isEmpty() && matchedSubgroups.isEmpty(); }
 8579            /** Returns the {@code ArgGroupSpec} of the container {@code MatchedGroup} of this multiple. */
 8580            public ArgGroupSpec group() { return container.group; }
 8581            /** Returns the container {@code MatchedGroup} of this multiple. */
 8582            public MatchedGroup container() { return container; }
 8583            /** Returns matches for the subgroups, if any. */
 8584            public Map<ArgGroupSpec, MatchedGroup> matchedSubgroups() { return Collections.unmodifiableMap(matchedSubgroups); }
 8585            int matchCount(ArgSpec argSpec)                    { return matchedValues.get(argSpec) == null ? 0 : matchedValues.get(argSpec).size(); }
 8586            /** Returns the values matched for the specified argument, converted to the type of the argument. */
 8587            public List<Object> matchedValues(ArgSpec argSpec) { return matchedValues.get(argSpec) == null ? Collections.emptyList() : Collections.unmodifiableList(matchedValues.get(argSpec)); }
 8588            void addOriginalStringValue(ArgSpec argSpec, String value) {
 8589                addValueToListInMap(originalStringValues, argSpec, value);
 8590            }
 8591            void addMatchedValue(ArgSpec argSpec, int matchPosition, Object stronglyTypedValue, Tracer tracer) {
 8592                addValueToListInMap(matchedValues, argSpec, stronglyTypedValue);
 8593
 8594                Map<Integer, List<Object>> positionalValues = matchedValuesAtPosition.get(argSpec);
 8595                if (positionalValues == null) {
 8596                    positionalValues = new TreeMap<Integer, List<Object>>();
 8597                    matchedValuesAtPosition.put(argSpec, positionalValues);
 8598                }
 8599                addValueToListInMap(positionalValues, matchPosition, stronglyTypedValue);
 8600            }
 8601            boolean hasMatchedValueAtPosition(ArgSpec arg, int position) { Map<Integer, List<Object>> atPos = matchedValuesAtPosition.get(arg); return atPos != null && atPos.containsKey(position); }
 8602
 8603            /** Returns {@code true} if the minimum number of elements have been matched for this multiple:
 8604             * all required arguments have been matched, and for each subgroup,
 8605             * the {@linkplain MatchedGroup#matchedMinElements() minimum number of elements have been matched}.*/
 8606            boolean matchedMinElements() { return matchedFully(false); }
 8607            /** Returns {@code true} if the maximum number of multiples has been matched for this multiple:
 8608             * all arguments (required or not) have been matched, and for each subgroup,
 8609             * the {@linkplain MatchedGroup#matchedMaxElements() maximum number of elements have been matched}.*/
 8610            boolean matchedMaxElements() { return matchedFully(true); }
 8611            private boolean matchedFully(boolean allRequired) {
 8612                if (group().exclusive()) { return !matchedValues.isEmpty() || hasFullyMatchedSubgroup(allRequired); }
 8613                for (ArgSpec arg : group().args()) {
 8614                    if (matchedValues.get(arg) == null && (arg.required() || allRequired)) { return false; }
 8615                }
 8616                for (ArgGroupSpec subgroup : group().subgroups()) {
 8617                    MatchedGroup matchedGroup = matchedSubgroups.get(subgroup);
 8618                    if (matchedGroup != null) {
 8619                        if (!matchedGroup.matchedFully(allRequired)) { return false; }
 8620                    } else {
 8621                        if (allRequired || subgroup.multiplicity().min > 0) { return false; }
 8622                    }
 8623                }
 8624                return true;
 8625            }
 8626            private boolean hasFullyMatchedSubgroup(boolean allRequired) {
 8627                for (MatchedGroup sub : matchedSubgroups.values()) { if (sub.matchedFully(allRequired)) { return true; } }
 8628                return false;
 8629            }
 8630            @Override public String toString() {
 8631                return toString(new StringBuilder()).toString();
 8632            }
 8633
 8634            private StringBuilder toString(StringBuilder result) {
 8635                int originalLength = result.length();
 8636                for (ArgSpec arg : originalStringValues.keySet()) {
 8637                    List<String> values = originalStringValues.get(arg);
 8638                    for (String value : values) {
 8639                        if (result.length() != originalLength) { result.append(" "); }
 8640                        result.append(ArgSpec.describe(arg, "=", value));
 8641                    }
 8642                }
 8643                for (MatchedGroup sub : matchedSubgroups.values()) {
 8644                    if (result.length() != originalLength) { result.append(" "); }
 8645                    if (originalLength == 0) {
 8646                        result.append(sub.toString()); // include synopsis
 8647                    } else {
 8648                        sub.toString(result); // without synopsis
 8649                    }
 8650                }
 8651                return result;
 8652            }
 8653        }
 8654    }
 8655    static <K, T> void addValueToListInMap(Map<K, List<T>> map, K key, T value) {
 8656        List<T> values = map.get(key);
 8657        if (values == null) { values = new ArrayList<T>(); map.put(key, values); }
 8658        values.add(value);
 8659    }
 8660    static <T> List<T> flatList(Collection<? extends Collection<T>> collection) {
 8661        List<T> result = new ArrayList<T>();
 8662        for (Collection<T> sub : collection) { result.addAll(sub); }
 8663        return result;
 8664    }
 8665    private enum LookBehind { SEPARATE, ATTACHED, ATTACHED_WITH_SEPARATOR;
 8666        public boolean isAttached() { return this != LookBehind.SEPARATE; }
 8667    }
 8668    /**
 8669     * Helper class responsible for processing command line arguments.
 8670     */
 8671    private class Interpreter {
 8672        private final Map<Class<?>, ITypeConverter<?>> converterRegistry = new HashMap<Class<?>, ITypeConverter<?>>();
 8673        private boolean isHelpRequested;
 8674        private int position;
 8675        private boolean endOfOptions;
 8676        private ParseResult.Builder parseResultBuilder;
 8677
 8678        Interpreter() { registerBuiltInConverters(); }
 8679
 8680        private void registerBuiltInConverters() {
 8681            converterRegistry.put(Object.class,        new BuiltIn.StringConverter());
 8682            converterRegistry.put(String.class,        new BuiltIn.StringConverter());
 8683            converterRegistry.put(StringBuilder.class, new BuiltIn.StringBuilderConverter());
 8684            converterRegistry.put(CharSequence.class,  new BuiltIn.CharSequenceConverter());
 8685            converterRegistry.put(Byte.class,          new BuiltIn.ByteConverter());
 8686            converterRegistry.put(Byte.TYPE,           new BuiltIn.ByteConverter());
 8687            converterRegistry.put(Boolean.class,       new BuiltIn.BooleanConverter());
 8688            converterRegistry.put(Boolean.TYPE,        new BuiltIn.BooleanConverter());
 8689            converterRegistry.put(Character.class,     new BuiltIn.CharacterConverter());
 8690            converterRegistry.put(Character.TYPE,      new BuiltIn.CharacterConverter());
 8691            converterRegistry.put(Short.class,         new BuiltIn.ShortConverter());
 8692            converterRegistry.put(Short.TYPE,          new BuiltIn.ShortConverter());
 8693            converterRegistry.put(Integer.class,       new BuiltIn.IntegerConverter());
 8694            converterRegistry.put(Integer.TYPE,        new BuiltIn.IntegerConverter());
 8695            converterRegistry.put(Long.class,          new BuiltIn.LongConverter());
 8696            converterRegistry.put(Long.TYPE,           new BuiltIn.LongConverter());
 8697            converterRegistry.put(Float.class,         new BuiltIn.FloatConverter());
 8698            converterRegistry.put(Float.TYPE,          new BuiltIn.FloatConverter());
 8699            converterRegistry.put(Double.class,        new BuiltIn.DoubleConverter());
 8700            converterRegistry.put(Double.TYPE,         new BuiltIn.DoubleConverter());
 8701            converterRegistry.put(File.class,          new BuiltIn.FileConverter());
 8702            converterRegistry.put(URI.class,           new BuiltIn.URIConverter());
 8703            converterRegistry.put(URL.class,           new BuiltIn.URLConverter());
 8704            converterRegistry.put(Date.class,          new BuiltIn.ISO8601DateConverter());
 8705            converterRegistry.put(BigDecimal.class,    new BuiltIn.BigDecimalConverter());
 8706            converterRegistry.put(BigInteger.class,    new BuiltIn.BigIntegerConverter());
 8707            converterRegistry.put(Charset.class,       new BuiltIn.CharsetConverter());
 8708            converterRegistry.put(InetAddress.class,   new BuiltIn.InetAddressConverter());
 8709            converterRegistry.put(Pattern.class,       new BuiltIn.PatternConverter());
 8710            converterRegistry.put(UUID.class,          new BuiltIn.UUIDConverter());
 8711            converterRegistry.put(Currency.class,      new BuiltIn.CurrencyConverter());
 8712            converterRegistry.put(TimeZone.class,      new BuiltIn.TimeZoneConverter());
 8713            converterRegistry.put(ByteOrder.class,     new BuiltIn.ByteOrderConverter());
 8714            converterRegistry.put(Class.class,         new BuiltIn.ClassConverter());
 8715            converterRegistry.put(NetworkInterface.class, new BuiltIn.NetworkInterfaceConverter());
 8716
 8717            BuiltIn.ISO8601TimeConverter.registerIfAvailable(converterRegistry, tracer);
 8718            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.sql.Connection", "java.sql.DriverManager","getConnection", String.class);
 8719            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.sql.Driver", "java.sql.DriverManager","getDriver", String.class);
 8720            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.sql.Timestamp", "java.sql.Timestamp","valueOf", String.class);
 8721
 8722            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.Duration", "parse", CharSequence.class);
 8723            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.Instant", "parse", CharSequence.class);
 8724            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.LocalDate", "parse", CharSequence.class);
 8725            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.LocalDateTime", "parse", CharSequence.class);
 8726            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.LocalTime", "parse", CharSequence.class);
 8727            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.MonthDay", "parse", CharSequence.class);
 8728            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.OffsetDateTime", "parse", CharSequence.class);
 8729            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.OffsetTime", "parse", CharSequence.class);
 8730            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.Period", "parse", CharSequence.class);
 8731            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.Year", "parse", CharSequence.class);
 8732            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.YearMonth", "parse", CharSequence.class);
 8733            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.ZonedDateTime", "parse", CharSequence.class);
 8734            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.ZoneId", "of", String.class);
 8735            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.ZoneOffset", "of", String.class);
 8736
 8737            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.nio.file.Path", "java.nio.file.Paths", "get", String.class, String[].class);
 8738        }
 8739        private ParserSpec config() { return commandSpec.parser(); }
 8740        /**
 8741         * Entry point into parsing command line arguments.
 8742         * @param args the command line arguments
 8743         * @return a list with all commands and subcommands initialized by this method
 8744         * @throws ParameterException if the specified command line arguments are invalid
 8745         */
 8746        List<CommandLine> parse(String... args) {
 8747            Assert.notNull(args, "argument array");
 8748            if (tracer.isInfo()) {tracer.info("Picocli version: %s%n", versionString());}
 8749            if (tracer.isInfo()) {tracer.info("Parsing %d command line args %s%n", args.length, Arrays.toString(args));}
 8750            if (tracer.isDebug()){tracer.debug("Parser configuration: %s%n", config());}
 8751            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",
 8752                    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"));}
 8753            List<String> expanded = new ArrayList<String>();
 8754            for (String arg : args) { addOrExpand(arg, expanded, new LinkedHashSet<String>()); }
 8755            Stack<String> arguments = new Stack<String>();
 8756            arguments.addAll(reverseList(expanded));
 8757            List<CommandLine> result = new ArrayList<CommandLine>();
 8758            parse(result, arguments, args, new ArrayList<Object>());
 8759            return result;
 8760        }
 8761
 8762        private void addOrExpand(String arg, List<String> arguments, Set<String> visited) {
 8763            if (config().expandAtFiles() && !arg.equals("@") && arg.startsWith("@")) {
 8764                arg = arg.substring(1);
 8765                if (arg.startsWith("@")) {
 8766                    if (tracer.isInfo()) { tracer.info("Not expanding @-escaped argument %s (trimmed leading '@' char)%n", arg); }
 8767                } else {
 8768                    if (tracer.isInfo()) { tracer.info("Expanding argument file @%s%n", arg); }
 8769                    expandArgumentFile(arg, arguments, visited);
 8770                    return;
 8771                }
 8772            }
 8773            arguments.add(arg);
 8774        }
 8775        private void expandArgumentFile(String fileName, List<String> arguments, Set<String> visited) {
 8776            File file = new File(fileName);
 8777            if (!file.canRead()) {
 8778                if (tracer.isInfo()) {tracer.info("File %s does not exist or cannot be read; treating argument literally%n", fileName);}
 8779                arguments.add("@" + fileName);
 8780            } else if (visited.contains(file.getAbsolutePath())) {
 8781                if (tracer.isInfo()) {tracer.info("Already visited file %s; ignoring...%n", file.getAbsolutePath());}
 8782            } else {
 8783                expandValidArgumentFile(fileName, file, arguments, visited);
 8784            }
 8785        }
 8786        private void expandValidArgumentFile(String fileName, File file, List<String> arguments, Set<String> visited) {
 8787            List<String> result = new ArrayList<String>();
 8788            LineNumberReader reader = null;
 8789            try {
 8790                visited.add(file.getAbsolutePath());
 8791                reader = new LineNumberReader(new FileReader(file));
 8792                if (commandSpec.parser().useSimplifiedAtFiles()) {
 8793                    String token;
 8794                    while ((token = reader.readLine()) != null) {
 8795                        if (token.length() > 0 && !token.trim().startsWith(String.valueOf(commandSpec.parser().atFileCommentChar()))) {
 8796                            addOrExpand(token, result, visited);
 8797                        }
 8798                    }
 8799                } else {
 8800                    StreamTokenizer tok = new StreamTokenizer(reader);
 8801                    tok.resetSyntax();
 8802                    tok.wordChars(' ', 255);
 8803                    tok.whitespaceChars(0, ' ');
 8804                    tok.quoteChar('"');
 8805                    tok.quoteChar('\'');
 8806                    if (commandSpec.parser().atFileCommentChar() != null) {
 8807                        tok.commentChar(commandSpec.parser().atFileCommentChar());
 8808                    }
 8809                    while (tok.nextToken() != StreamTokenizer.TT_EOF) {
 8810                        addOrExpand(tok.sval, result, visited);
 8811                    }
 8812                }
 8813            } catch (Exception ex) {
 8814                throw new InitializationException("Could not read argument file @" + fileName, ex);
 8815            } finally {
 8816                if (reader != null) { try {reader.close();} catch (Exception ignored) {} }
 8817            }
 8818            if (tracer.isInfo()) {tracer.info("Expanded file @%s to arguments %s%n", fileName, result);}
 8819            arguments.addAll(result);
 8820        }
 8821        private void clear() {
 8822            position = 0;
 8823            endOfOptions = false;
 8824            isHelpRequested = false;
 8825            parseResultBuilder = ParseResult.builder(getCommandSpec());
 8826            for (OptionSpec option : getCommandSpec().options())                           { clear(option); }
 8827            for (PositionalParamSpec positional : getCommandSpec().positionalParameters()) { clear(positional); }
 8828        }
 8829        private void clear(ArgSpec argSpec) {
 8830            argSpec.resetStringValues();
 8831            argSpec.resetOriginalStringValues();
 8832            argSpec.typedValues.clear();
 8833            argSpec.typedValueAtPosition.clear();
 8834            if (argSpec.group() == null) { argSpec.applyInitialValue(tracer); } // groups do their own initialization
 8835        }
 8836
 8837        private void maybeThrow(PicocliException ex) throws PicocliException {
 8838            if (commandSpec.parser().collectErrors) {
 8839                parseResultBuilder.addError(ex);
 8840            } else {
 8841                throw ex;
 8842            }
 8843        }
 8844
 8845        private void parse(List<CommandLine> parsedCommands, Stack<String> argumentStack, String[] originalArgs, List<Object> nowProcessing) {
 8846            clear(); // first reset any state in case this CommandLine instance is being reused
 8847            if (tracer.isDebug()) {
 8848                tracer.debug("Initializing %s: %d options, %d positional parameters, %d required, %d groups, %d subcommands.%n",
 8849                        commandSpec.toString(), new HashSet<ArgSpec>(commandSpec.optionsMap().values()).size(),
 8850                        commandSpec.positionalParameters().size(), commandSpec.requiredArgs().size(),
 8851                        commandSpec.argGroups().size(), commandSpec.subcommands().size());
 8852            }
 8853            parsedCommands.add(CommandLine.this);
 8854            List<ArgSpec> required = new ArrayList<ArgSpec>(commandSpec.requiredArgs());
 8855            Set<ArgSpec> initialized = new LinkedHashSet<ArgSpec>();
 8856            Collections.sort(required, new PositionalParametersSorter());
 8857            boolean continueOnError = commandSpec.parser().collectErrors();
 8858            do {
 8859                int stackSize = argumentStack.size();
 8860                try {
 8861                    applyDefaultValues(required);
 8862                    processArguments(parsedCommands, argumentStack, required, initialized, originalArgs, nowProcessing);
 8863                } catch (ParameterException ex) {
 8864                    maybeThrow(ex);
 8865                } catch (Exception ex) {
 8866                    int offendingArgIndex = originalArgs.length - argumentStack.size() - 1;
 8867                    String arg = offendingArgIndex >= 0 && offendingArgIndex < originalArgs.length ? originalArgs[offendingArgIndex] : "?";
 8868                    maybeThrow(ParameterException.create(CommandLine.this, ex, arg, offendingArgIndex, originalArgs));
 8869                }
 8870                if (continueOnError && stackSize == argumentStack.size() && stackSize > 0) {
 8871                    parseResultBuilder.unmatched.add(argumentStack.pop());
 8872                }
 8873            } while (!argumentStack.isEmpty() && continueOnError);
 8874
 8875            if (!isAnyHelpRequested()) {
 8876                validateConstraints(argumentStack, required, initialized);
 8877            }
 8878        }
 8879
 8880        private void validateConstraints(Stack<String> argumentStack, List<ArgSpec> required, Set<ArgSpec> matched) {
 8881            if (!required.isEmpty()) {
 8882                for (ArgSpec missing : required) {
 8883                    Assert.assertTrue(missing.group() == null, "Arguments in a group are not necessarily required for the command");
 8884                    if (missing.isOption()) {
 8885                        maybeThrow(MissingParameterException.create(CommandLine.this, required, config().separator()));
 8886                    } else {
 8887                        assertNoMissingParameters(missing, missing.arity(), argumentStack);
 8888                    }
 8889                }
 8890            }
 8891            if (!parseResultBuilder.unmatched.isEmpty()) {
 8892                String[] unmatched = parseResultBuilder.unmatched.toArray(new String[0]);
 8893                for (UnmatchedArgsBinding unmatchedArgsBinding : getCommandSpec().unmatchedArgsBindings()) {
 8894                    unmatchedArgsBinding.addAll(unmatched.clone());
 8895                }
 8896                if (!isUnmatchedArgumentsAllowed()) { maybeThrow(new UnmatchedArgumentException(CommandLine.this, Collections.unmodifiableList(parseResultBuilder.unmatched))); }
 8897                if (tracer.isInfo()) { tracer.info("Unmatched arguments: %s%n", parseResultBuilder.unmatched); }
 8898            }
 8899            for (ArgGroupSpec group : commandSpec.argGroups()) {
 8900                group.clearValidationResult();
 8901            }
 8902            ParseResult pr = parseResultBuilder.build();
 8903            for (ArgGroupSpec group : commandSpec.argGroups()) {
 8904                group.validateConstraints(pr);
 8905            }
 8906            List<ParseResult.MatchedGroupMultiple> matchedGroupMultiples = pr.getMatchedGroupMultiples();
 8907            if (matchedGroupMultiples.size() > 1) {
 8908                failGroupMultiplicityExceeded(matchedGroupMultiples);
 8909            }
 8910        }
 8911
 8912        private void failGroupMultiplicityExceeded(List<ParseResult.MatchedGroupMultiple> matchedGroupMultiples) {
 8913            Map<ArgGroupSpec, List<List<ParseResult.MatchedGroupMultiple>>> multiplesPerGroup = new IdentityHashMap<ArgGroupSpec, List<List<ParseResult.MatchedGroupMultiple>>>();
 8914            String msg = "";
 8915            for (ParseResult.MatchedGroupMultiple multiple : matchedGroupMultiples) {
 8916                if (msg.length() > 0) { msg += " and "; }
 8917                msg += multiple.toString();
 8918                Map<ArgGroupSpec, MatchedGroup> subgroups = multiple.matchedSubgroups();
 8919                for (ArgGroupSpec group : subgroups.keySet()) {
 8920                    addValueToListInMap(multiplesPerGroup, group, subgroups.get(group).multiples());
 8921                }
 8922            }
 8923            if (!simplifyErrorMessageForSingleGroup(multiplesPerGroup)) {
 8924                maybeThrow(new MaxValuesExceededException(CommandLine.this, "Error: expected only one match but got " + msg));
 8925            }
 8926        }
 8927
 8928        private boolean simplifyErrorMessageForSingleGroup(Map<ArgGroupSpec, List<List<ParseResult.MatchedGroupMultiple>>> multiplesPerGroup) {
 8929            if (multiplesPerGroup.size() == 1) { // all multiples were matches for a single group
 8930                ArgGroupSpec group = multiplesPerGroup.keySet().iterator().next();
 8931                List<ParseResult.MatchedGroupMultiple> flat = flatList(multiplesPerGroup.get(group));
 8932                for (ParseResult.MatchedGroupMultiple multiple : flat) {
 8933                    if (!multiple.matchedSubgroups().isEmpty()) { return false; }
 8934                }
 8935                group.validationException = null;
 8936                group.validateMultiples(CommandLine.this, flat);
 8937                if (group.validationException != null) {
 8938                    maybeThrow(group.validationException);
 8939                    return true;
 8940                }
 8941            }
 8942            return false;
 8943        }
 8944
 8945        private void applyDefaultValues(List<ArgSpec> required) throws Exception {
 8946            parseResultBuilder.isInitializingDefaultValues = true;
 8947            for (ArgSpec arg : commandSpec.args()) {
 8948                if (arg.group() == null) {
 8949                    if (applyDefault(commandSpec.defaultValueProvider(), arg)) { required.remove(arg); }
 8950                }
 8951            }
 8952            parseResultBuilder.isInitializingDefaultValues = false;
 8953        }
 8954
 8955        private boolean applyDefault(IDefaultValueProvider defaultValueProvider, ArgSpec arg) throws Exception {
 8956
 8957            // Default value provider return value is only used if provider exists and if value
 8958            // is not null otherwise the original default or initial value are used
 8959            String fromProvider = defaultValueProvider == null ? null : defaultValueProvider.defaultValue(arg);
 8960            String defaultValue = fromProvider == null ? arg.defaultValue() : fromProvider;
 8961
 8962            if (defaultValue != null) {
 8963                if (tracer.isDebug()) {tracer.debug("Applying defaultValue (%s) to %s%n", defaultValue, arg);}
 8964                Range arity = arg.arity().min(Math.max(1, arg.arity().min));
 8965                applyOption(arg, LookBehind.SEPARATE, arity, stack(defaultValue), new HashSet<ArgSpec>(), arg.toString);
 8966            }
 8967            return defaultValue != null;
 8968        }
 8969
 8970        private Stack<String> stack(String value) {Stack<String> result = new Stack<String>(); result.push(value); return result;}
 8971
 8972        private void processArguments(List<CommandLine> parsedCommands,
 8973                                      Stack<String> args,
 8974                                      Collection<ArgSpec> required,
 8975                                      Set<ArgSpec> initialized,
 8976                                      String[] originalArgs,
 8977                                      List<Object> nowProcessing) throws Exception {
 8978            // arg must be one of:
 8979            // 1. the "--" double dash separating options from positional arguments
 8980            // 1. a stand-alone flag, like "-v" or "--verbose": no value required, must map to boolean or Boolean field
 8981            // 2. a short option followed by an argument, like "-f file" or "-ffile": may map to any type of field
 8982            // 3. a long option followed by an argument, like "-file out.txt" or "-file=out.txt"
 8983            // 3. one or more remaining arguments without any associated options. Must be the last in the list.
 8984            // 4. a combination of stand-alone options, like "-vxr". Equivalent to "-v -x -r", "-v true -x true -r true"
 8985            // 5. a combination of stand-alone options and one option with an argument, like "-vxrffile"
 8986
 8987            parseResultBuilder.originalArgs(originalArgs);
 8988            parseResultBuilder.nowProcessing = nowProcessing;
 8989            String separator = config().separator();
 8990            while (!args.isEmpty()) {
 8991                if (endOfOptions) {
 8992                    processRemainderAsPositionalParameters(required, initialized, args);
 8993                    return;
 8994                }
 8995                String arg = args.pop();
 8996                if (tracer.isDebug()) {tracer.debug("Processing argument '%s'. Remainder=%s%n", arg, reverse(copy(args)));}
 8997
 8998                // Double-dash separates options from positional arguments.
 8999                // If found, then interpret the remaining args as positional parameters.
 9000                if (commandSpec.parser.endOfOptionsDelimiter().equals(arg)) {
 9001                    tracer.info("Found end-of-options delimiter '--'. Treating remainder as positional parameters.%n");
 9002                    endOfOptions = true;
 9003                    processRemainderAsPositionalParameters(required, initialized, args);
 9004                    return; // we are done
 9005                }
 9006
 9007                // if we find another command, we are done with the current command
 9008                if (commandSpec.subcommands().containsKey(arg)) {
 9009                    CommandLine subcommand = commandSpec.subcommands().get(arg);
 9010                    nowProcessing.add(subcommand.commandSpec);
 9011                    updateHelpRequested(subcommand.commandSpec);
 9012                    if (!isAnyHelpRequested() && !required.isEmpty()) { // ensure current command portion is valid
 9013                        throw MissingParameterException.create(CommandLine.this, required, separator);
 9014                    }
 9015                    if (tracer.isDebug()) {tracer.debug("Found subcommand '%s' (%s)%n", arg, subcommand.commandSpec.toString());}
 9016                    subcommand.interpreter.parse(parsedCommands, args, originalArgs, nowProcessing);
 9017                    parseResultBuilder.subcommand(subcommand.interpreter.parseResultBuilder.build());
 9018                    return; // remainder done by the command
 9019                }
 9020
 9021                // First try to interpret the argument as a single option (as opposed to a compact group of options).
 9022                // A single option may be without option parameters, like "-v" or "--verbose" (a boolean value),
 9023                // or an option may have one or more option parameters.
 9024                // A parameter may be attached to the option.
 9025                boolean paramAttachedToOption = false;
 9026                int separatorIndex = arg.indexOf(separator);
 9027                if (separatorIndex > 0) {
 9028                    String key = arg.substring(0, separatorIndex);
 9029                    // be greedy. Consume the whole arg as an option if possible.
 9030                    if (commandSpec.optionsMap().containsKey(key) && commandSpec.optionsMap().containsKey(arg)) {
 9031                        tracer.warn("Both '%s' and '%s' are valid option names in %s. Using '%s'...%n", arg, key, getCommandName(), arg);
 9032                    } else if (commandSpec.optionsMap().containsKey(key)) {
 9033                        paramAttachedToOption = true;
 9034                        String optionParam = arg.substring(separatorIndex + separator.length());
 9035                        args.push(optionParam);
 9036                        arg = key;
 9037                        if (tracer.isDebug()) {tracer.debug("Separated '%s' option from '%s' option parameter%n", key, optionParam);}
 9038                    } else {
 9039                        if (tracer.isDebug()) {tracer.debug("'%s' contains separator '%s' but '%s' is not a known option%n", arg, separator, key);}
 9040                    }
 9041                } else {
 9042                    if (tracer.isDebug()) {tracer.debug("'%s' cannot be separated into <option>%s<option-parameter>%n", arg, separator);}
 9043                }
 9044                if (isStandaloneOption(arg)) {
 9045                    processStandaloneOption(required, initialized, arg, args, paramAttachedToOption);
 9046                }
 9047                // Compact (single-letter) options can be grouped with other options or with an argument.
 9048                // only single-letter options can be combined with other options or with an argument
 9049                else if (config().posixClusteredShortOptionsAllowed() && arg.length() > 2 && arg.startsWith("-")) {
 9050                    if (tracer.isDebug()) {tracer.debug("Trying to process '%s' as clustered short options%n", arg, args);}
 9051                    processClusteredShortOptions(required, initialized, arg, args);
 9052                }
 9053                // The argument could not be interpreted as an option: process it as a positional argument
 9054                else {
 9055                    args.push(arg);
 9056                    if (tracer.isDebug()) {tracer.debug("Could not find option '%s', deciding whether to treat as unmatched option or positional parameter...%n", arg);}
 9057                    if (commandSpec.resemblesOption(arg, tracer)) { handleUnmatchedArgument(args); continue; } // #149
 9058                    if (tracer.isDebug()) {tracer.debug("No option named '%s' found. Processing as positional parameter%n", arg);}
 9059                    processPositionalParameter(required, initialized, args);
 9060                }
 9061            }
 9062        }
 9063
 9064        private boolean isStandaloneOption(String arg) {
 9065            return commandSpec.optionsMap().containsKey(arg);
 9066        }
 9067        private void handleUnmatchedArgument(Stack<String> args) throws Exception {
 9068            if (!args.isEmpty()) { handleUnmatchedArgument(args.pop()); }
 9069            if (config().stopAtUnmatched()) {
 9070                // addAll would give args in reverse order
 9071                while (!args.isEmpty()) { handleUnmatchedArgument(args.pop()); }
 9072            }
 9073        }
 9074        private void handleUnmatchedArgument(String arg) {
 9075            parseResultBuilder.unmatched.add(arg);
 9076        }
 9077
 9078        private void processRemainderAsPositionalParameters(Collection<ArgSpec> required, Set<ArgSpec> initialized, Stack<String> args) throws Exception {
 9079            while (!args.empty()) {
 9080                processPositionalParameter(required, initialized, args);
 9081            }
 9082        }
 9083        private void processPositionalParameter(Collection<ArgSpec> required, Set<ArgSpec> initialized, Stack<String> args) throws Exception {
 9084            if (tracer.isDebug()) {tracer.debug("Processing next arg as a positional parameter. Command-local position=%d. Remainder=%s%n", position, reverse(copy(args)));}
 9085            if (config().stopAtPositional()) {
 9086                if (!endOfOptions && tracer.isDebug()) {tracer.debug("Parser was configured with stopAtPositional=true, treating remaining arguments as positional parameters.%n");}
 9087                endOfOptions = true;
 9088            }
 9089            int consumedByGroup = 0;
 9090            int argsConsumed = 0;
 9091            int interactiveConsumed = 0;
 9092            int originalNowProcessingSize = parseResultBuilder.nowProcessing.size();
 9093            Map<PositionalParamSpec, Integer> newPositions = new IdentityHashMap<PositionalParamSpec, Integer>();
 9094            for (PositionalParamSpec positionalParam : commandSpec.positionalParameters()) {
 9095                Range indexRange = positionalParam.index();
 9096                int localPosition = getPosition(positionalParam);
 9097                if (positionalParam.group() != null) { // does the positionalParam's index range contain the current position in the currently matching group
 9098                    MatchedGroup matchedGroup = parseResultBuilder.matchedGroup.findOrCreateMatchingGroup(positionalParam, commandSpec.commandLine());
 9099                    if (!indexRange.contains(localPosition) || (matchedGroup != null && matchedGroup.multiple().hasMatchedValueAtPosition(positionalParam, localPosition))) {
 9100                        continue;
 9101                    }
 9102                } else {
 9103                    if (!indexRange.contains(localPosition) || positionalParam.typedValueAtPosition.get(localPosition) != null) {
 9104                        continue;
 9105                    }
 9106                }
 9107                Stack<String> argsCopy = copy(args);
 9108                Range arity = positionalParam.arity();
 9109                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);}
 9110                if (!assertNoMissingParameters(positionalParam, arity, argsCopy)) { break; } // #389 collectErrors parsing
 9111                int originalSize = argsCopy.size();
 9112                int actuallyConsumed = applyOption(positionalParam, LookBehind.SEPARATE, arity, argsCopy, initialized, "args[" + indexRange + "] at position " + localPosition);
 9113                int count = originalSize - argsCopy.size();
 9114                if (count > 0 || actuallyConsumed > 0) {
 9115                    required.remove(positionalParam);
 9116                    if (positionalParam.interactive()) { interactiveConsumed++; }
 9117                }
 9118                if (positionalParam.group() == null) { // don't update the command-level position for group args
 9119                    argsConsumed = Math.max(argsConsumed, count);
 9120                } else {
 9121                    newPositions.put(positionalParam, localPosition + count);
 9122                    consumedByGroup = Math.max(consumedByGroup, count);
 9123                }
 9124                while (parseResultBuilder.nowProcessing.size() > originalNowProcessingSize + count) {
 9125                    parseResultBuilder.nowProcessing.remove(parseResultBuilder.nowProcessing.size() - 1);
 9126                }
 9127            }
 9128            // remove processed args from the stack
 9129            int maxConsumed = Math.max(consumedByGroup, argsConsumed);
 9130            for (int i = 0; i < maxConsumed; i++) { args.pop(); }
 9131            position += argsConsumed + interactiveConsumed;
 9132            if (tracer.isDebug()) {tracer.debug("Consumed %d arguments and %d interactive values, moving command-local position to index %d.%n", argsConsumed, interactiveConsumed, position);}
 9133            for (PositionalParamSpec positional : newPositions.keySet()) {
 9134                MatchedGroup inProgress = parseResultBuilder.matchedGroup.findOrCreateMatchingGroup(positional, commandSpec.commandLine());
 9135                if (inProgress != null) {
 9136                    inProgress.multiple().position = newPositions.get(positional);
 9137                    if (tracer.isDebug()) {tracer.debug("Updated group position to %s for group %s.%n", inProgress.multiple().position, inProgress);}
 9138                }
 9139            }
 9140            if (consumedByGroup == 0 && argsConsumed == 0 && interactiveConsumed == 0 && !args.isEmpty()) {
 9141                handleUnmatchedArgument(args);
 9142            }
 9143        }
 9144
 9145        private void processStandaloneOption(Collection<ArgSpec> required,
 9146                                             Set<ArgSpec> initialized,
 9147                                             String arg,
 9148                                             Stack<String> args,
 9149                                             boolean paramAttachedToKey) throws Exception {
 9150            ArgSpec argSpec = commandSpec.optionsMap().get(arg);
 9151            required.remove(argSpec);
 9152            Range arity = argSpec.arity();
 9153            if (paramAttachedToKey) {
 9154                arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1
 9155            }
 9156            LookBehind lookBehind = paramAttachedToKey ? LookBehind.ATTACHED_WITH_SEPARATOR : LookBehind.SEPARATE;
 9157            if (tracer.isDebug()) {tracer.debug("Found option named '%s': %s, arity=%s%n", arg, argSpec, arity);}
 9158            parseResultBuilder.nowProcessing.add(argSpec);
 9159            applyOption(argSpec, lookBehind, arity, args, initialized, "option " + arg);
 9160        }
 9161
 9162        private void processClusteredShortOptions(Collection<ArgSpec> required,
 9163                                                  Set<ArgSpec> initialized,
 9164                                                  String arg,
 9165                                                  Stack<String> args) throws Exception {
 9166            String prefix = arg.substring(0, 1);
 9167            String cluster = arg.substring(1);
 9168            boolean paramAttachedToOption = true;
 9169            boolean first = true;
 9170            do {
 9171                if (cluster.length() > 0 && commandSpec.posixOptionsMap().containsKey(cluster.charAt(0))) {
 9172                    ArgSpec argSpec = commandSpec.posixOptionsMap().get(cluster.charAt(0));
 9173                    Range arity = argSpec.arity();
 9174                    String argDescription = "option " + prefix + cluster.charAt(0);
 9175                    if (tracer.isDebug()) {tracer.debug("Found option '%s%s' in %s: %s, arity=%s%n", prefix, cluster.charAt(0), arg,
 9176                            argSpec, arity);}
 9177                    required.remove(argSpec);
 9178                    cluster = cluster.substring(1);
 9179                    paramAttachedToOption = cluster.length() > 0;
 9180                    LookBehind lookBehind = paramAttachedToOption ? LookBehind.ATTACHED : LookBehind.SEPARATE;
 9181                    if (cluster.startsWith(config().separator())) {// attached with separator, like -f=FILE or -v=true
 9182                        lookBehind = LookBehind.ATTACHED_WITH_SEPARATOR;
 9183                        cluster = cluster.substring(config().separator().length());
 9184                        arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1
 9185                    }
 9186                    if (arity.min > 0 && !empty(cluster)) {
 9187                        if (tracer.isDebug()) {tracer.debug("Trying to process '%s' as option parameter%n", cluster);}
 9188                    }
 9189                    // arity may be >= 1, or
 9190                    // arity <= 0 && !cluster.startsWith(separator)
 9191                    // e.g., boolean @Option("-v", arity=0, varargs=true); arg "-rvTRUE", remainder cluster="TRUE"
 9192                    if (!empty(cluster)) {
 9193                        args.push(cluster); // interpret remainder as option parameter (CAUTION: may be empty string!)
 9194                    }
 9195                    if (first) {
 9196                        parseResultBuilder.nowProcessing.add(argSpec);
 9197                        first = false;
 9198                    } else {
 9199                        parseResultBuilder.nowProcessing.set(parseResultBuilder.nowProcessing.size() - 1, argSpec); // replace
 9200                    }
 9201                    int argCount = args.size();
 9202                    int consumed = applyOption(argSpec, lookBehind, arity, args, initialized, argDescription);
 9203                    // 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
 9204                    if (empty(cluster) || args.isEmpty() || args.size() < argCount) {
 9205                        return;
 9206                    }
 9207                    cluster = args.pop();
 9208                } else { // cluster is empty || cluster.charAt(0) is not a short option key
 9209                    if (cluster.length() == 0) { // we finished parsing a group of short options like -rxv
 9210                        return; // return normally and parse the next arg
 9211                    }
 9212                    // We get here when the remainder of the cluster group is neither an option,
 9213                    // nor a parameter that the last option could consume.
 9214                    if (arg.endsWith(cluster)) {
 9215                        args.push(paramAttachedToOption ? prefix + cluster : cluster);
 9216                        if (args.peek().equals(arg)) { // #149 be consistent between unmatched short and long options
 9217                            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);}
 9218                            if (commandSpec.resemblesOption(arg, tracer)) { handleUnmatchedArgument(args); return; } // #149
 9219                            processPositionalParameter(required, initialized, args);
 9220                            return;
 9221                        }
 9222                        // remainder was part of a clustered group that could not be completely parsed
 9223                        if (tracer.isDebug()) {tracer.debug("No option found for %s in %s%n", cluster, arg);}
 9224                        String tmp = args.pop();
 9225                        tmp = tmp + " (while processing option: '" + arg + "')";
 9226                        args.push(tmp);
 9227                        handleUnmatchedArgument(args);
 9228                    } else {
 9229                        args.push(cluster);
 9230                        if (tracer.isDebug()) {tracer.debug("%s is not an option parameter for %s%n", cluster, arg);}
 9231                        processPositionalParameter(required, initialized, args);
 9232                    }
 9233                    return;
 9234                }
 9235            } while (true);
 9236        }
 9237
 9238        private int applyOption(ArgSpec argSpec,
 9239                                LookBehind lookBehind,
 9240                                Range arity,
 9241                                Stack<String> args,
 9242                                Set<ArgSpec> initialized,
 9243                                String argDescription) throws Exception {
 9244            updateHelpRequested(argSpec);
 9245            boolean consumeOnlyOne = commandSpec.parser().aritySatisfiedByAttachedOptionParam() && lookBehind.isAttached();
 9246            Stack<String> workingStack = args;
 9247            if (consumeOnlyOne) {
 9248                workingStack = args.isEmpty() ? args : stack(args.pop());
 9249            } else {
 9250                if (!assertNoMissingParameters(argSpec, arity, args)) { return 0; } // #389 collectErrors parsing
 9251            }
 9252
 9253            if (argSpec.interactive()) {
 9254                String name = argSpec.isOption() ? ((OptionSpec) argSpec).longestName() : "position " + position;
 9255                String prompt = String.format("Enter value for %s (%s): ", name, str(argSpec.renderedDescription(), 0));
 9256                if (tracer.isDebug()) {tracer.debug("Reading value for %s from console...%n", name);}
 9257                char[] value = readPassword(prompt);
 9258                if (tracer.isDebug()) {tracer.debug("User entered '%s' for %s.%n", value, name);}
 9259                workingStack.push(new String(value));
 9260            }
 9261
 9262            parseResultBuilder.beforeMatchingGroupElement(argSpec);
 9263
 9264            int result;
 9265            if (argSpec.type().isArray()) {
 9266                result = applyValuesToArrayField(argSpec, lookBehind, arity, workingStack, initialized, argDescription);
 9267            } else if (Collection.class.isAssignableFrom(argSpec.type())) {
 9268                result = applyValuesToCollectionField(argSpec, lookBehind, arity, workingStack, initialized, argDescription);
 9269            } else if (Map.class.isAssignableFrom(argSpec.type())) {
 9270                result = applyValuesToMapField(argSpec, lookBehind, arity, workingStack, initialized, argDescription);
 9271            } else {
 9272                result = applyValueToSingleValuedField(argSpec, lookBehind, arity, workingStack, initialized, argDescription);
 9273            }
 9274            if (workingStack != args && !workingStack.isEmpty()) {
 9275                args.push(workingStack.pop());
 9276                Assert.assertTrue(workingStack.isEmpty(), "Working stack should be empty but was " + new ArrayList<String>(workingStack));
 9277            }
 9278            return result;
 9279        }
 9280
 9281        private int applyValueToSingleValuedField(ArgSpec argSpec,
 9282                                                  LookBehind lookBehind,
 9283                                                  Range derivedArity,
 9284                                                  Stack<String> args,
 9285                                                  Set<ArgSpec> initialized,
 9286                                                  String argDescription) throws Exception {
 9287            boolean noMoreValues = args.isEmpty();
 9288            String value = args.isEmpty() ? null : trim(args.pop()); // unquote the value
 9289            Range arity = argSpec.arity().isUnspecified ? derivedArity : argSpec.arity(); // #509
 9290            if (arity.max == 0 && !arity.isUnspecified && lookBehind == LookBehind.ATTACHED_WITH_SEPARATOR) { // #509
 9291                throw new MaxValuesExceededException(CommandLine.this, optionDescription("", argSpec, 0) +
 9292                        " should be specified without '" + value + "' parameter");
 9293            }
 9294            int result = arity.min; // the number or args we need to consume
 9295
 9296            Class<?> cls = argSpec.auxiliaryTypes()[0]; // field may be interface/abstract type, use annotation to get concrete type
 9297            if (arity.min <= 0) { // value may be optional
 9298
 9299                // special logic for booleans: BooleanConverter accepts only "true" or "false".
 9300                if (cls == Boolean.class || cls == Boolean.TYPE) {
 9301
 9302                    // boolean option with arity = 0..1 or 0..*: value MAY be a param
 9303                    if (arity.max > 0 && ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value))) {
 9304                        result = 1;            // if it is a varargs we only consume 1 argument if it is a boolean value
 9305                        if (!lookBehind.isAttached()) { parseResultBuilder.nowProcessing(argSpec, value); }
 9306                    } else if (lookBehind != LookBehind.ATTACHED_WITH_SEPARATOR) { // if attached, try converting the value to boolean (and fail if invalid value)
 9307                        // it's okay to ignore value if not attached to option
 9308                        if (value != null) {
 9309                            args.push(value); // we don't consume the value
 9310                        }
 9311                        if (commandSpec.parser().toggleBooleanFlags()) {
 9312                            Boolean currentValue = (Boolean) argSpec.getValue();
 9313                            value = String.valueOf(currentValue == null || !currentValue); // #147 toggle existing boolean value
 9314                        } else {
 9315                            value = "true";
 9316                        }
 9317                    }
 9318                } else { // non-boolean option with optional value #325, #279
 9319                    if (isOption(value)) {
 9320                        args.push(value); // we don't consume the value
 9321                        value = "";
 9322                    } else if (value == null) {
 9323                        value = "";
 9324                    } else {
 9325                        if (!lookBehind.isAttached()) { parseResultBuilder.nowProcessing(argSpec, value); }
 9326                    }
 9327                }
 9328            } else {
 9329                if (!lookBehind.isAttached()) { parseResultBuilder.nowProcessing(argSpec, value); }
 9330            }
 9331            if (noMoreValues && value == null) {
 9332                return 0;
 9333            }
 9334            ITypeConverter<?> converter = getTypeConverter(cls, argSpec, 0);
 9335            Object newValue = tryConvert(argSpec, -1, converter, value, cls);
 9336            Object oldValue = argSpec.getValue();
 9337            String traceMessage = "Setting %s to '%3$s' (was '%2$s') for %4$s%n";
 9338            if (argSpec.group() == null && initialized.contains(argSpec)) {
 9339                if (!isOverwrittenOptionsAllowed()) {
 9340                    throw new OverwrittenOptionException(CommandLine.this, argSpec, optionDescription("", argSpec, 0) +  " should be specified only once");
 9341                }
 9342                traceMessage = "Overwriting %s value '%s' with '%s' for %s%n";
 9343            }
 9344            initialized.add(argSpec);
 9345
 9346            if (tracer.isInfo()) { tracer.info(traceMessage, argSpec.toString(), String.valueOf(oldValue), String.valueOf(newValue), argDescription); }
 9347            int pos = getPosition(argSpec);
 9348            argSpec.setValue(newValue);
 9349            parseResultBuilder.addOriginalStringValue(argSpec, value);// #279 track empty string value if no command line argument was consumed
 9350            parseResultBuilder.addStringValue(argSpec, value);
 9351            parseResultBuilder.addTypedValues(argSpec, pos, newValue);
 9352            parseResultBuilder.add(argSpec, pos);
 9353            return result;
 9354        }
 9355        private int applyValuesToMapField(ArgSpec argSpec,
 9356                                          LookBehind lookBehind,
 9357                                          Range arity,
 9358                                          Stack<String> args,
 9359                                          Set<ArgSpec> initialized,
 9360                                          String argDescription) throws Exception {
 9361            Class<?>[] classes = argSpec.auxiliaryTypes();
 9362            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); }
 9363            ITypeConverter<?> keyConverter   = getTypeConverter(classes[0], argSpec, 0);
 9364            ITypeConverter<?> valueConverter = getTypeConverter(classes[1], argSpec, 1);
 9365            @SuppressWarnings("unchecked") Map<Object, Object> map = (Map<Object, Object>) argSpec.getValue();
 9366            if (map == null || (!map.isEmpty() && !initialized.contains(argSpec))) {
 9367                tracer.debug("Initializing binding for %s with empty %s%n", optionDescription("", argSpec, 0), argSpec.type().getSimpleName());
 9368                map = createMap(argSpec.type()); // map class
 9369                argSpec.setValue(map);
 9370            }
 9371            initialized.add(argSpec);
 9372            int originalSize = map.size();
 9373            int pos = getPosition(argSpec);
 9374            consumeMapArguments(argSpec, lookBehind, arity, args, classes, keyConverter, valueConverter, map, argDescription);
 9375            parseResultBuilder.add(argSpec, pos);
 9376            argSpec.setValue(map);
 9377            return map.size() - originalSize;
 9378        }
 9379
 9380        private void consumeMapArguments(ArgSpec argSpec,
 9381                                         LookBehind lookBehind,
 9382                                         Range arity,
 9383                                         Stack<String> args,
 9384                                         Class<?>[] classes,
 9385                                         ITypeConverter<?> keyConverter,
 9386                                         ITypeConverter<?> valueConverter,
 9387                                         Map<Object, Object> result,
 9388                                         String argDescription) throws Exception {
 9389
 9390            // don't modify Interpreter.position: same position may be consumed by multiple ArgSpec objects
 9391            int currentPosition = getPosition(argSpec);
 9392
 9393            // first do the arity.min mandatory parameters
 9394            int initialSize = argSpec.stringValues().size();
 9395            int consumed = consumedCountMap(0, initialSize, argSpec);
 9396            for (int i = 0; consumed < arity.min && !args.isEmpty(); i++) {
 9397                Map<Object, Object> typedValuesAtPosition = new LinkedHashMap<Object, Object>();
 9398                parseResultBuilder.addTypedValues(argSpec, currentPosition++, typedValuesAtPosition);
 9399                assertNoMissingMandatoryParameter(argSpec, args, i, arity);
 9400                consumeOneMapArgument(argSpec, lookBehind, arity, consumed, args.pop(), classes, keyConverter, valueConverter, typedValuesAtPosition, i, argDescription);
 9401                result.putAll(typedValuesAtPosition);
 9402                consumed = consumedCountMap(i + 1, initialSize, argSpec);
 9403                lookBehind = LookBehind.SEPARATE;
 9404            }
 9405            // now process the varargs if any
 9406            for (int i = consumed; consumed < arity.max && !args.isEmpty(); i++) {
 9407                if (!varargCanConsumeNextValue(argSpec, args.peek())) { break; }
 9408
 9409                Map<Object, Object> typedValuesAtPosition = new LinkedHashMap<Object, Object>();
 9410                parseResultBuilder.addTypedValues(argSpec, currentPosition++, typedValuesAtPosition);
 9411                if (!canConsumeOneMapArgument(argSpec, arity, consumed, args.peek(), classes, keyConverter, valueConverter, argDescription)) {
 9412                    break; // leave empty map at argSpec.typedValueAtPosition[currentPosition] so we won't try to consume that position again
 9413                }
 9414                consumeOneMapArgument(argSpec, lookBehind, arity, consumed, args.pop(), classes, keyConverter, valueConverter, typedValuesAtPosition, i, argDescription);
 9415                result.putAll(typedValuesAtPosition);
 9416                consumed = consumedCountMap(i + 1, initialSize, argSpec);
 9417                lookBehind = LookBehind.SEPARATE;
 9418            }
 9419        }
 9420
 9421        private void consumeOneMapArgument(ArgSpec argSpec,
 9422                                           LookBehind lookBehind,
 9423                                           Range arity, int consumed,
 9424                                           String arg,
 9425                                           Class<?>[] classes,
 9426                                           ITypeConverter<?> keyConverter, ITypeConverter<?> valueConverter,
 9427                                           Map<Object, Object> result,
 9428                                           int index,
 9429                                           String argDescription) throws Exception {
 9430            if (!lookBehind.isAttached()) { parseResultBuilder.nowProcessing(argSpec, arg); }
 9431            String raw = trim(arg);
 9432            String[] values = argSpec.splitValue(raw, commandSpec.parser(), arity, consumed);
 9433            for (String value : values) {
 9434                String[] keyValue = splitKeyValue(argSpec, value);
 9435                Object mapKey =   tryConvert(argSpec, index, keyConverter,   keyValue[0], classes[0]);
 9436                Object mapValue = tryConvert(argSpec, index, valueConverter, keyValue[1], classes[1]);
 9437                result.put(mapKey, mapValue);
 9438                if (tracer.isInfo()) { tracer.info("Putting [%s : %s] in %s<%s, %s> %s for %s%n", String.valueOf(mapKey), String.valueOf(mapValue),
 9439                        result.getClass().getSimpleName(), classes[0].getSimpleName(), classes[1].getSimpleName(), argSpec.toString(), argDescription); }
 9440                parseResultBuilder.addStringValue(argSpec, keyValue[0]);
 9441                parseResultBuilder.addStringValue(argSpec, keyValue[1]);
 9442            }
 9443            parseResultBuilder.addOriginalStringValue(argSpec, raw);
 9444        }
 9445
 9446        private boolean canConsumeOneMapArgument(ArgSpec argSpec, Range arity, int consumed,
 9447                                                 String raw, Class<?>[] classes,
 9448                                                 ITypeConverter<?> keyConverter, ITypeConverter<?> valueConverter,
 9449                                                 String argDescription) {
 9450            String[] values = argSpec.splitValue(raw, commandSpec.parser(), arity, consumed);
 9451            try {
 9452                for (String value : values) {
 9453                    String[] keyValue = splitKeyValue(argSpec, value);
 9454                    tryConvert(argSpec, -1, keyConverter, keyValue[0], classes[0]);
 9455                    tryConvert(argSpec, -1, valueConverter, keyValue[1], classes[1]);
 9456                }
 9457                return true;
 9458            } catch (PicocliException ex) {
 9459                tracer.debug("$s cannot be assigned to %s: type conversion fails: %s.%n", raw, argDescription, ex.getMessage());
 9460                return false;
 9461            }
 9462        }
 9463
 9464        private String[] splitKeyValue(ArgSpec argSpec, String value) {
 9465            String[] keyValue = ArgSpec.splitRespectingQuotedStrings(value, 2, config(), argSpec, "=");
 9466
 9467                if (keyValue.length < 2) {
 9468                String splitRegex = argSpec.splitRegex();
 9469                if (splitRegex.length() == 0) {
 9470                    throw new ParameterException(CommandLine.this, "Value for option " + optionDescription("",
 9471                            argSpec, 0) + " should be in KEY=VALUE format but was " + value, argSpec, value);
 9472                } else {
 9473                    throw new ParameterException(CommandLine.this, "Value for option " + optionDescription("",
 9474                            argSpec, 0) + " should be in KEY=VALUE[" + splitRegex + "KEY=VALUE]... format but was " + value, argSpec, value);
 9475                }
 9476            }
 9477            return keyValue;
 9478        }
 9479
 9480        private void assertNoMissingMandatoryParameter(ArgSpec argSpec, Stack<String> args, int i, Range arity) {
 9481            if (!varargCanConsumeNextValue(argSpec, args.peek())) {
 9482                String desc = arity.min > 1 ? (i + 1) + " (of " + arity.min + " mandatory parameters) " : "";
 9483                throw new MissingParameterException(CommandLine.this, argSpec, "Expected parameter " + desc + "for " + optionDescription("", argSpec, -1) + " but found '" + args.peek() + "'");
 9484            }
 9485        }
 9486        private int applyValuesToArrayField(ArgSpec argSpec,
 9487                                            LookBehind lookBehind,
 9488                                            Range arity,
 9489                                            Stack<String> args,
 9490                                            Set<ArgSpec> initialized,
 9491                                            String argDescription) throws Exception {
 9492            Object existing = argSpec.getValue();
 9493            int length = existing == null ? 0 : Array.getLength(existing);
 9494            Class<?> type = argSpec.auxiliaryTypes()[0];
 9495            int pos = getPosition(argSpec);
 9496            List<Object> converted = consumeArguments(argSpec, lookBehind, arity, args, type, argDescription);
 9497            List<Object> newValues = new ArrayList<Object>();
 9498            if (initialized.contains(argSpec)) { // existing values are default values if initialized does NOT contain argsSpec
 9499                for (int i = 0; i < length; i++) {
 9500                    newValues.add(Array.get(existing, i)); // keep non-default values
 9501                }
 9502            }
 9503            initialized.add(argSpec);
 9504            for (Object obj : converted) {
 9505                if (obj instanceof Collection<?>) {
 9506                    newValues.addAll((Collection<?>) obj);
 9507                } else {
 9508                    newValues.add(obj);
 9509                }
 9510            }
 9511            Object array = Array.newInstance(type, newValues.size());
 9512            for (int i = 0; i < newValues.size(); i++) {
 9513                Array.set(array, i, newValues.get(i));
 9514            }
 9515            argSpec.setValue(array);
 9516            parseResultBuilder.add(argSpec, pos);
 9517            return converted.size(); // return how many args were consumed
 9518        }
 9519
 9520        @SuppressWarnings("unchecked")
 9521        private int applyValuesToCollectionField(ArgSpec argSpec,
 9522                                                 LookBehind lookBehind,
 9523                                                 Range arity,
 9524                                                 Stack<String> args,
 9525                                                 Set<ArgSpec> initialized,
 9526                                                 String argDescription) throws Exception {
 9527            Collection<Object> collection = (Collection<Object>) argSpec.getValue();
 9528            Class<?> type = argSpec.auxiliaryTypes()[0];
 9529            int pos = getPosition(argSpec);
 9530            List<Object> converted = consumeArguments(argSpec, lookBehind, arity, args, type, argDescription);
 9531            if (collection == null || (!collection.isEmpty() && !initialized.contains(argSpec))) {
 9532                tracer.debug("Initializing binding for %s with empty %s%n", optionDescription("", argSpec, 0), argSpec.type().getSimpleName());
 9533                collection = createCollection(argSpec.type(), type); // collection type, element type
 9534                argSpec.setValue(collection);
 9535            }
 9536            initialized.add(argSpec);
 9537            for (Object element : converted) {
 9538                if (element instanceof Collection<?>) {
 9539                    collection.addAll((Collection<?>) element);
 9540                } else {
 9541                    collection.add(element);
 9542                }
 9543            }
 9544            parseResultBuilder.add(argSpec, pos);
 9545            argSpec.setValue(collection);
 9546            return converted.size();
 9547        }
 9548
 9549        private List<Object> consumeArguments(ArgSpec argSpec,
 9550                                              LookBehind lookBehind,
 9551                                              Range arity,
 9552                                              Stack<String> args,
 9553                                              Class<?> type,
 9554                                              String argDescription) throws Exception {
 9555            List<Object> result = new ArrayList<Object>();
 9556
 9557            // don't modify Interpreter.position: same position may be consumed by multiple ArgSpec objects
 9558            int currentPosition = getPosition(argSpec);
 9559
 9560            // first do the arity.min mandatory parameters
 9561            int initialSize = argSpec.stringValues().size();
 9562            int consumed = consumedCount(0, initialSize, argSpec);
 9563            for (int i = 0; consumed < arity.min && !args.isEmpty(); i++) {
 9564                List<Object> typedValuesAtPosition = new ArrayList<Object>();
 9565                parseResultBuilder.addTypedValues(argSpec, currentPosition++, typedValuesAtPosition);
 9566                assertNoMissingMandatoryParameter(argSpec, args, i, arity);
 9567                consumeOneArgument(argSpec, lookBehind, arity, consumed, args.pop(), type, typedValuesAtPosition, i, argDescription);
 9568                result.addAll(typedValuesAtPosition);
 9569                consumed = consumedCount(i + 1, initialSize, argSpec);
 9570                lookBehind = LookBehind.SEPARATE;
 9571            }
 9572            // now process the varargs if any
 9573            for (int i = consumed; consumed < arity.max && !args.isEmpty(); i++) {
 9574                if (!varargCanConsumeNextValue(argSpec, args.peek())) { break; }
 9575
 9576                List<Object> typedValuesAtPosition = new ArrayList<Object>();
 9577                parseResultBuilder.addTypedValues(argSpec, currentPosition++, typedValuesAtPosition);
 9578                if (!canConsumeOneArgument(argSpec, arity, consumed, args.peek(), type, argDescription)) {
 9579                    break; // leave empty list at argSpec.typedValueAtPosition[currentPosition] so we won't try to consume that position again
 9580                }
 9581                consumeOneArgument(argSpec, lookBehind, arity, consumed, args.pop(), type, typedValuesAtPosition, i, argDescription);
 9582                result.addAll(typedValuesAtPosition);
 9583                consumed = consumedCount(i + 1, initialSize, argSpec);
 9584                lookBehind = LookBehind.SEPARATE;
 9585            }
 9586            if (result.isEmpty() && arity.min == 0 && arity.max <= 1 && isBoolean(type)) {
 9587                return Arrays.asList((Object) Boolean.TRUE);
 9588            }
 9589            return result;
 9590        }
 9591
 9592        private int consumedCount(int i, int initialSize, ArgSpec arg) {
 9593            return commandSpec.parser().splitFirst() ? arg.stringValues().size() - initialSize : i;
 9594        }
 9595
 9596        private int consumedCountMap(int i, int initialSize, ArgSpec arg) {
 9597            return commandSpec.parser().splitFirst() ? (arg.stringValues().size() - initialSize) / 2 : i;
 9598        }
 9599
 9600        private int consumeOneArgument(ArgSpec argSpec,
 9601                                       LookBehind lookBehind,
 9602                                       Range arity,
 9603                                       int consumed,
 9604                                       String arg,
 9605                                       Class<?> type,
 9606                                       List<Object> result,
 9607                                       int index,
 9608                                       String argDescription) {
 9609            if (!lookBehind.isAttached()) { parseResultBuilder.nowProcessing(argSpec, arg); }
 9610            String raw = trim(arg);
 9611            String[] values = argSpec.splitValue(raw, commandSpec.parser(), arity, consumed);
 9612            ITypeConverter<?> converter = getTypeConverter(type, argSpec, 0);
 9613            for (int j = 0; j < values.length; j++) {
 9614                Object stronglyTypedValue = tryConvert(argSpec, index, converter, values[j], type);
 9615                result.add(stronglyTypedValue);
 9616                if (tracer.isInfo()) {
 9617                    tracer.info("Adding [%s] to %s for %s%n", String.valueOf(result.get(result.size() - 1)), argSpec.toString(), argDescription);
 9618                }
 9619                parseResultBuilder.addStringValue(argSpec, values[j]);
 9620            }
 9621            parseResultBuilder.addOriginalStringValue(argSpec, raw);
 9622            return ++index;
 9623        }
 9624        private boolean canConsumeOneArgument(ArgSpec argSpec, Range arity, int consumed, String arg, Class<?> type, String argDescription) {
 9625            ITypeConverter<?> converter = getTypeConverter(type, argSpec, 0);
 9626            try {
 9627                String[] values = argSpec.splitValue(trim(arg), commandSpec.parser(), arity, consumed);
 9628//                if (!argSpec.acceptsValues(values.length, commandSpec.parser())) {
 9629//                    tracer.debug("$s would split into %s values but %s cannot accept that many values.%n", arg, values.length, argDescription);
 9630//                    return false;
 9631//                }
 9632                for (String value : values) {
 9633                    tryConvert(argSpec, -1, converter, value, type);
 9634                }
 9635                return true;
 9636            } catch (PicocliException ex) {
 9637                tracer.debug("$s cannot be assigned to %s: type conversion fails: %s.%n", arg, argDescription, ex.getMessage());
 9638                return false;
 9639            }
 9640        }
 9641
 9642        /** Returns whether the next argument can be assigned to a vararg option/positional parameter.
 9643         * <p>
 9644         * Usually, we stop if we encounter '--', a command, or another option.
 9645         * However, if end-of-options has been reached, positional parameters may consume all remaining arguments. </p>*/
 9646        private boolean varargCanConsumeNextValue(ArgSpec argSpec, String nextValue) {
 9647            if (endOfOptions && argSpec.isPositional()) { return true; }
 9648            boolean isCommand = commandSpec.subcommands().containsKey(nextValue);
 9649            return !isCommand && !isOption(nextValue);
 9650        }
 9651
 9652        /**
 9653         * Called when parsing varargs parameters for a multi-value option.
 9654         * When an option is encountered, the remainder should not be interpreted as vararg elements.
 9655         * @param arg the string to determine whether it is an option or not
 9656         * @return true if it is an option, false otherwise
 9657         */
 9658        private boolean isOption(String arg) {
 9659            if (arg == null)      { return false; }
 9660            if ("--".equals(arg)) { return true; }
 9661
 9662            // not just arg prefix: we may be in the middle of parsing -xrvfFILE
 9663            if (commandSpec.optionsMap().containsKey(arg)) { // -v or -f or --file (not attached to param or other option)
 9664                return true;
 9665            }
 9666            int separatorIndex = arg.indexOf(config().separator());
 9667            if (separatorIndex > 0) { // -f=FILE or --file==FILE (attached to param via separator)
 9668                if (commandSpec.optionsMap().containsKey(arg.substring(0, separatorIndex))) {
 9669                    return true;
 9670                }
 9671            }
 9672            return (arg.length() > 2 && arg.startsWith("-") && commandSpec.posixOptionsMap().containsKey(arg.charAt(1)));
 9673        }
 9674        private Object tryConvert(ArgSpec argSpec, int index, ITypeConverter<?> converter, String value, Class<?> type)
 9675                throws ParameterException {
 9676            try {
 9677                return converter.convert(value);
 9678            } catch (TypeConversionException ex) {
 9679                String msg = String.format("Invalid value for %s: %s", optionDescription("", argSpec, index), ex.getMessage());
 9680                throw new ParameterException(CommandLine.this, msg, argSpec, value);
 9681            } catch (Exception other) {
 9682                String desc = optionDescription("", argSpec, index);
 9683                String msg = String.format("Invalid value for %s: cannot convert '%s' to %s (%s)", desc, value, type.getSimpleName(), other);
 9684                throw new ParameterException(CommandLine.this, msg, other, argSpec, value);
 9685            }
 9686        }
 9687
 9688        private String optionDescription(String prefix, ArgSpec argSpec, int index) {
 9689            String desc = "";
 9690            if (argSpec.isOption()) {
 9691                desc = prefix + "option '" + ((OptionSpec) argSpec).longestName() + "'";
 9692                if (index >= 0) {
 9693                    if (argSpec.arity().max > 1) {
 9694                        desc += " at index " + index;
 9695                    }
 9696                    desc += " (" + argSpec.paramLabel() + ")";
 9697                }
 9698            } else {
 9699                desc = prefix + "positional parameter at index " + ((PositionalParamSpec) argSpec).index() + " (" + argSpec.paramLabel() + ")";
 9700            }
 9701            return desc;
 9702        }
 9703
 9704        private boolean isAnyHelpRequested() { return isHelpRequested || parseResultBuilder.versionHelpRequested || parseResultBuilder.usageHelpRequested; }
 9705
 9706        private void updateHelpRequested(CommandSpec command) {
 9707            isHelpRequested |= command.helpCommand();
 9708        }
 9709        private void updateHelpRequested(ArgSpec argSpec) {
 9710            if (!parseResultBuilder.isInitializingDefaultValues && argSpec.isOption()) {
 9711                OptionSpec option = (OptionSpec) argSpec;
 9712                isHelpRequested                  |= is(argSpec, "help", option.help());
 9713                parseResultBuilder.versionHelpRequested |= is(argSpec, "versionHelp", option.versionHelp());
 9714                parseResultBuilder.usageHelpRequested   |= is(argSpec, "usageHelp", option.usageHelp());
 9715            }
 9716        }
 9717        private boolean is(ArgSpec p, String attribute, boolean value) {
 9718            if (value) { if (tracer.isInfo()) {tracer.info("%s has '%s' annotation: not validating required fields%n", p.toString(), attribute); }}
 9719            return value;
 9720        }
 9721        @SuppressWarnings("unchecked")
 9722        private Collection<Object> createCollection(Class<?> collectionClass, Class<?> elementType) throws Exception {
 9723            if (EnumSet.class.isAssignableFrom(collectionClass) && Enum.class.isAssignableFrom(elementType)) {
 9724                Object enumSet = EnumSet.noneOf((Class<Enum>) elementType);
 9725                return (Collection<Object>) enumSet;
 9726            }
 9727            // custom Collection implementation class must have default constructor
 9728            return (Collection<Object>) factory.create(collectionClass);
 9729        }
 9730        @SuppressWarnings("unchecked") private Map<Object, Object> createMap(Class<?> mapClass) throws Exception {
 9731            return (Map<Object, Object>) factory.create(mapClass);
 9732        }
 9733        private ITypeConverter<?> getTypeConverter(final Class<?> type, ArgSpec argSpec, int index) {
 9734            if (argSpec.converters().length > index) { return argSpec.converters()[index]; }
 9735            if (converterRegistry.containsKey(type)) { return converterRegistry.get(type); }
 9736            if (type.isEnum()) {
 9737                return new ITypeConverter<Object>() {
 9738                    @SuppressWarnings("unchecked")
 9739                    public Object convert(String value) throws Exception {
 9740                        String sensitivity = "case-sensitive";
 9741                        if (commandSpec.parser().caseInsensitiveEnumValuesAllowed()) {
 9742                            String upper = value.toUpperCase();
 9743                            for (Object enumConstant : type.getEnumConstants()) {
 9744                                if (upper.equals(String.valueOf(enumConstant).toUpperCase())) { return enumConstant; }
 9745                            }
 9746                            sensitivity = "case-insensitive";
 9747                        }
 9748                        try { return Enum.valueOf((Class<Enum>) type, value); }
 9749                        catch (Exception ex) {
 9750                            Enum<?>[] constants = ((Class<Enum<?>>) type).getEnumConstants();
 9751                            String[] names = new String[constants.length];
 9752                            for (int i = 0; i < names.length; i++) { names[i] = constants[i].name(); }
 9753                            throw new TypeConversionException(
 9754                                String.format("expected one of %s (%s) but was '%s'", Arrays.asList(names), sensitivity, value)); }
 9755                    }
 9756                };
 9757            }
 9758            throw new MissingTypeConverterException(CommandLine.this, "No TypeConverter registered for " + type.getName() + " of " + argSpec);
 9759        }
 9760
 9761        private boolean assertNoMissingParameters(ArgSpec argSpec, Range arity, Stack<String> args) {
 9762            if (argSpec.interactive()) { return true; }
 9763            int available = args.size();
 9764            if (available > 0 && commandSpec.parser().splitFirst() && argSpec.splitRegex().length() > 0) {
 9765                available += argSpec.splitValue(args.peek(), commandSpec.parser(), arity, 0).length - 1;
 9766            }
 9767            if (arity.min > available) {
 9768                if (arity.min == 1) {
 9769                    if (argSpec.isOption()) {
 9770                        maybeThrow(new MissingParameterException(CommandLine.this, argSpec, "Missing required parameter for " +
 9771                                optionDescription("", argSpec, 0)));
 9772                        return false;
 9773                    }
 9774                    Range indexRange = ((PositionalParamSpec) argSpec).index();
 9775                    String sep = "";
 9776                    String names = ": ";
 9777                    int count = 0;
 9778                    List<PositionalParamSpec> positionalParameters = commandSpec.positionalParameters();
 9779                    for (int i = indexRange.min; i < positionalParameters.size(); i++) {
 9780                        if (positionalParameters.get(i).arity().min > 0) {
 9781                            names += sep + positionalParameters.get(i).paramLabel();
 9782                            sep = ", ";
 9783                            count++;
 9784                        }
 9785                    }
 9786                    String msg = "Missing required parameter";
 9787                    Range paramArity = argSpec.arity();
 9788                    if (count > 1 || arity.min - available > 1) {
 9789                        msg += "s";
 9790                    }
 9791                    maybeThrow(new MissingParameterException(CommandLine.this, argSpec, msg + names));
 9792                } else if (args.isEmpty()) {
 9793                    maybeThrow(new MissingParameterException(CommandLine.this, argSpec, optionDescription("", argSpec, 0) +
 9794                            " requires at least " + arity.min + " values, but none were specified."));
 9795                } else {
 9796                    maybeThrow(new MissingParameterException(CommandLine.this, argSpec, optionDescription("", argSpec, 0) +
 9797                            " requires at least " + arity.min + " values, but only " + available + " were specified: " + reverse(args)));
 9798                }
 9799                return false;
 9800            }
 9801            return true;
 9802        }
 9803        private String trim(String value) {
 9804            return unquote(value);
 9805        }
 9806
 9807        private String unquote(String value) {
 9808            if (!commandSpec.parser().trimQuotes()) { return value; }
 9809            return value == null
 9810                    ? null
 9811                    : (value.length() > 1 && value.startsWith("\"") && value.endsWith("\""))
 9812                        ? value.substring(1, value.length() - 1)
 9813                        : value;
 9814        }
 9815
 9816        char[] readPassword(String prompt) {
 9817            try {
 9818                Object console = System.class.getDeclaredMethod("console").invoke(null);
 9819                Method method = Class.forName("java.io.Console").getDeclaredMethod("readPassword", String.class, Object[].class);
 9820                return (char[]) method.invoke(console, prompt, new Object[0]);
 9821            } catch (Exception e) {
 9822                System.out.print(prompt);
 9823                InputStreamReader isr = new InputStreamReader(System.in);
 9824                BufferedReader in = new BufferedReader(isr);
 9825                try {
 9826                    return in.readLine().toCharArray();
 9827                } catch (IOException ex2) {
 9828                    throw new IllegalStateException(ex2);
 9829                }
 9830            }
 9831        }
 9832        int getPosition(ArgSpec arg) {
 9833            if (arg.group() == null) { return position; }
 9834            MatchedGroup matchedGroup = parseResultBuilder.matchedGroup.findOrCreateMatchingGroup(arg, commandSpec.commandLine());
 9835            return matchedGroup == null ? 0 : matchedGroup.multiple().position;
 9836        }
 9837        String positionDesc(ArgSpec arg) {
 9838            int pos = getPosition(arg);
 9839            return (arg.group() == null) ? pos + " (command-local)" : pos + " (in group " + arg.group().synopsis() + ")";
 9840        }
 9841    }
 9842    private static class PositionalParametersSorter implements Comparator<ArgSpec> {
 9843        private static final Range OPTION_INDEX = new Range(0, 0, false, true, "0");
 9844        public int compare(ArgSpec p1, ArgSpec p2) {
 9845            int result = index(p1).compareTo(index(p2));
 9846            return (result == 0) ? p1.arity().compareTo(p2.arity()) : result;
 9847        }
 9848        private Range index(ArgSpec arg) { return arg.isOption() ? OPTION_INDEX : ((PositionalParamSpec) arg).index(); }
 9849    }
 9850    /**
 9851     * Inner class to group the built-in {@link ITypeConverter} implementations.
 9852     */
 9853    private static class BuiltIn {
 9854        static class StringConverter implements ITypeConverter<String> {
 9855            public String convert(String value) { return value; }
 9856        }
 9857        static class StringBuilderConverter implements ITypeConverter<StringBuilder> {
 9858            public StringBuilder convert(String value) { return new StringBuilder(value); }
 9859        }
 9860        static class CharSequenceConverter implements ITypeConverter<CharSequence> {
 9861            public String convert(String value) { return value; }
 9862        }
 9863        /** Converts {@code "true"} or {@code "false"} to a {@code Boolean}. Other values result in a ParameterException.*/
 9864        static class BooleanConverter implements ITypeConverter<Boolean> {
 9865            public Boolean convert(String value) {
 9866                if ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value)) {
 9867                    return Boolean.parseBoolean(value);
 9868                } else {
 9869                    throw new TypeConversionException("'" + value + "' is not a boolean");
 9870                }
 9871            }
 9872        }
 9873        static class CharacterConverter implements ITypeConverter<Character> {
 9874            public Character convert(String value) {
 9875                if (value.length() > 1) {
 9876                    throw new TypeConversionException("'" + value + "' is not a single character");
 9877                }
 9878                return value.charAt(0);
 9879            }
 9880        }
 9881        private static TypeConversionException fail(String value, Class<?> c) { return fail(value, c, "'%s' is not a %s"); }
 9882        private static TypeConversionException fail(String value, Class<?> c, String template) {
 9883            return new TypeConversionException(String.format(template, value, c.getSimpleName()));
 9884        }
 9885        /** Converts text to a {@code Byte} by delegating to {@link Byte#valueOf(String)}.*/
 9886        static class ByteConverter implements ITypeConverter<Byte> {
 9887            public Byte convert(String value) { try {return Byte.valueOf(value);} catch (Exception ex) {throw fail(value, Byte.TYPE);} }
 9888        }
 9889        /** Converts text to a {@code Short} by delegating to {@link Short#valueOf(String)}.*/
 9890        static class ShortConverter implements ITypeConverter<Short> {
 9891            public Short convert(String value) { try {return Short.valueOf(value);} catch (Exception ex) {throw fail(value, Short.TYPE);}  }
 9892        }
 9893        /** Converts text to an {@code Integer} by delegating to {@link Integer#valueOf(String)}.*/
 9894        static class IntegerConverter implements ITypeConverter<Integer> {
 9895            public Integer convert(String value) { try {return Integer.valueOf(value);} catch (Exception ex) {throw fail(value, Integer.TYPE, "'%s' is not an %s");}  }
 9896        }
 9897        /** Converts text to a {@code Long} by delegating to {@link Long#valueOf(String)}.*/
 9898        static class LongConverter implements ITypeConverter<Long> {
 9899            public Long convert(String value) { try {return Long.valueOf(value);} catch (Exception ex) {throw fail(value, Long.TYPE);}  }
 9900        }
 9901        static class FloatConverter implements ITypeConverter<Float> {
 9902            public Float convert(String value) { try {return Float.valueOf(value);} catch (Exception ex) {throw fail(value, Float.TYPE);}  }
 9903        }
 9904        static class DoubleConverter implements ITypeConverter<Double> {
 9905            public Double convert(String value) { try {return Double.valueOf(value);} catch (Exception ex) {throw fail(value, Double.TYPE);}  }
 9906        }
 9907        static class FileConverter implements ITypeConverter<File> {
 9908            public File convert(String value) { return new File(value); }
 9909        }
 9910        static class URLConverter implements ITypeConverter<URL> {
 9911            public URL convert(String value) throws MalformedURLException { return new URL(value); }
 9912        }
 9913        static class URIConverter implements ITypeConverter<URI> {
 9914            public URI convert(String value) throws URISyntaxException { return new URI(value); }
 9915        }
 9916        /** Converts text in {@code yyyy-mm-dd} format to a {@code java.util.Date}. ParameterException on failure. */
 9917        static class ISO8601DateConverter implements ITypeConverter<Date> {
 9918            public Date convert(String value) {
 9919                try {
 9920                    return new SimpleDateFormat("yyyy-MM-dd").parse(value);
 9921                } catch (ParseException e) {
 9922                    throw new TypeConversionException("'" + value + "' is not a yyyy-MM-dd date");
 9923                }
 9924            }
 9925        }
 9926        /** Converts text in any of the following formats to a {@code java.sql.Time}: {@code HH:mm}, {@code HH:mm:ss},
 9927         * {@code HH:mm:ss.SSS}, {@code HH:mm:ss,SSS}. Other formats result in a ParameterException. */
 9928        static class ISO8601TimeConverter implements ITypeConverter<Object> {
 9929            // Implementation note: use reflection so that picocli only requires the java.base module in Java 9.
 9930            private static /*final*/ String FQCN = "java.sql.Time"; // non-final for testing
 9931            public Object convert(String value) {
 9932                try {
 9933                    if (value.length() <= 5) {
 9934                        return createTime(new SimpleDateFormat("HH:mm").parse(value).getTime());
 9935                    } else if (value.length() <= 8) {
 9936                        return createTime(new SimpleDateFormat("HH:mm:ss").parse(value).getTime());
 9937                    } else if (value.length() <= 12) {
 9938                        try {
 9939                            return createTime(new SimpleDateFormat("HH:mm:ss.SSS").parse(value).getTime());
 9940                        } catch (ParseException e2) {
 9941                            return createTime(new SimpleDateFormat("HH:mm:ss,SSS").parse(value).getTime());
 9942                        }
 9943                    }
 9944                } catch (ParseException ignored) {
 9945                    // ignored because we throw a ParameterException below
 9946                }
 9947                throw new TypeConversionException("'" + value + "' is not a HH:mm[:ss[.SSS]] time");
 9948            }
 9949
 9950            private Object createTime(long epochMillis) {
 9951                try {
 9952                    Class<?> timeClass = Class.forName(FQCN);
 9953                    Constructor<?> constructor = timeClass.getDeclaredConstructor(long.class);
 9954                    return constructor.newInstance(epochMillis);
 9955                } catch (Exception e) {
 9956                    throw new TypeConversionException("Unable to create new java.sql.Time with long value " + epochMillis + ": " + e.getMessage());
 9957                }
 9958            }
 9959
 9960            public static void registerIfAvailable(Map<Class<?>, ITypeConverter<?>> registry, Tracer tracer) {
 9961                if (excluded(FQCN, tracer)) { return; }
 9962                try {
 9963                    registry.put(Class.forName(FQCN), new ISO8601TimeConverter());
 9964                } catch (Exception e) {
 9965                    if (!traced.contains(FQCN)) {
 9966                        tracer.debug("Could not register converter for %s: %s%n", FQCN, e.toString());
 9967                    }
 9968                    traced.add(FQCN);
 9969                }
 9970            }
 9971        }
 9972        static class BigDecimalConverter implements ITypeConverter<BigDecimal> {
 9973            public BigDecimal convert(String value) { return new BigDecimal(value); }
 9974        }
 9975        static class BigIntegerConverter implements ITypeConverter<BigInteger> {
 9976            public BigInteger convert(String value) { return new BigInteger(value); }
 9977        }
 9978        static class CharsetConverter implements ITypeConverter<Charset> {
 9979            public Charset convert(String s) { return Charset.forName(s); }
 9980        }
 9981        /** Converts text to a {@code InetAddress} by delegating to {@link InetAddress#getByName(String)}. */
 9982        static class InetAddressConverter implements ITypeConverter<InetAddress> {
 9983            public InetAddress convert(String s) throws Exception { return InetAddress.getByName(s); }
 9984        }
 9985        static class PatternConverter implements ITypeConverter<Pattern> {
 9986            public Pattern convert(String s) { return Pattern.compile(s); }
 9987        }
 9988        static class UUIDConverter implements ITypeConverter<UUID> {
 9989            public UUID convert(String s) throws Exception { return UUID.fromString(s); }
 9990        }
 9991        static class CurrencyConverter implements ITypeConverter<Currency> {
 9992            public Currency convert(String s) throws Exception { return Currency.getInstance(s); }
 9993        }
 9994        static class TimeZoneConverter implements ITypeConverter<TimeZone> {
 9995            public TimeZone convert(String s) throws Exception { return TimeZone.getTimeZone(s); }
 9996        }
 9997        static class ByteOrderConverter implements ITypeConverter<ByteOrder> {
 9998            public ByteOrder convert(String s) throws Exception {
 9999                if (s.equalsIgnoreCase(ByteOrder.BIG_ENDIAN.toString())) { return ByteOrder.BIG_ENDIAN; }
10000                if (s.equalsIgnoreCase(ByteOrder.LITTLE_ENDIAN.toString())) { return ByteOrder.LITTLE_ENDIAN; }
10001                throw new TypeConversionException("'" + s + "' is not a valid ByteOrder");
10002            }
10003        }
10004        static class ClassConverter implements ITypeConverter<Class<?>> {
10005            public Class<?> convert(String s) throws Exception { return Class.forName(s); }
10006        }
10007        static class NetworkInterfaceConverter implements ITypeConverter<NetworkInterface> {
10008            public NetworkInterface convert(String s) throws Exception {
10009                try {
10010                    InetAddress addr = new InetAddressConverter().convert(s);
10011                    return NetworkInterface.getByInetAddress(addr);
10012                } catch (Exception ex) {
10013                    try { return NetworkInterface.getByName(s);
10014                    } catch (Exception ex2) {
10015                        throw new TypeConversionException("'" + s + "' is not an InetAddress or NetworkInterface name");
10016                    }
10017                }
10018            }
10019        }
10020        static void registerIfAvailable(Map<Class<?>, ITypeConverter<?>> registry, Tracer tracer, String fqcn, String factoryMethodName, Class<?>... paramTypes) {
10021            registerIfAvailable(registry, tracer, fqcn, fqcn, factoryMethodName, paramTypes);
10022        }
10023        static void registerIfAvailable(Map<Class<?>, ITypeConverter<?>> registry, Tracer tracer, String fqcn, String factoryClass, String factoryMethodName, Class<?>... paramTypes) {
10024            if (excluded(fqcn, tracer)) { return; }
10025            try {
10026                Class<?> cls = Class.forName(fqcn);
10027                Class<?> factory = Class.forName(factoryClass);
10028                Method method = factory.getDeclaredMethod(factoryMethodName, paramTypes);
10029                registry.put(cls, new ReflectionConverter(method, paramTypes));
10030            } catch (Exception e) {
10031                if (!traced.contains(fqcn)) {
10032                    tracer.debug("Could not register converter for %s: %s%n", fqcn, e.toString());
10033                }
10034                traced.add(fqcn);
10035            }
10036        }
10037        static boolean excluded(String fqcn, Tracer tracer) {
10038            String[] excludes = System.getProperty("picocli.converters.excludes", "").split(",");
10039            for (String regex : excludes) {
10040                if (fqcn.matches(regex)) {
10041                    tracer.debug("BuiltIn type converter for %s is not loaded: (picocli.converters.excludes=%s)%n", fqcn, System.getProperty("picocli.converters.excludes"));
10042                    return true;
10043                }
10044            }
10045            return false;
10046        }
10047        static Set<String> traced = new HashSet<String>();
10048        static class ReflectionConverter implements ITypeConverter<Object> {
10049            private final Method method;
10050            private Class<?>[] paramTypes;
10051
10052            public ReflectionConverter(Method method, Class<?>... paramTypes) {
10053                this.method = Assert.notNull(method, "method");
10054                this.paramTypes = Assert.notNull(paramTypes, "paramTypes");
10055            }
10056
10057            public Object convert(String s) {
10058                try {
10059                    if (paramTypes.length > 1) {
10060                        return method.invoke(null, s, new String[0]);
10061                    } else {
10062                        return method.invoke(null, s);
10063                    }
10064                } catch (InvocationTargetException e) {
10065                    throw new TypeConversionException(String.format("cannot convert '%s' to %s (%s)", s, method.getReturnType(), e.getTargetException()));
10066                } catch (Exception e) {
10067                    throw new TypeConversionException(String.format("Internal error converting '%s' to %s (%s)", s, method.getReturnType(), e));
10068                }
10069            }
10070        }
10071        private BuiltIn() {} // private constructor: never instantiate
10072    }
10073
10074    static class AutoHelpMixin {
10075        private static final String KEY = "mixinStandardHelpOptions";
10076
10077        @Option(names = {"-h", "--help"}, usageHelp = true, descriptionKey = "mixinStandardHelpOptions.help",
10078                description = "Show this help message and exit.")
10079        private boolean helpRequested;
10080
10081        @Option(names = {"-V", "--version"}, versionHelp = true, descriptionKey = "mixinStandardHelpOptions.version",
10082                description = "Print version information and exit.")
10083        private boolean versionRequested;
10084    }
10085
10086    /** Help command that can be installed as a subcommand on all application commands. When invoked with a subcommand
10087     * argument, it prints usage help for the specified subcommand. For example:<pre>
10088     *
10089     * // print help for subcommand
10090     * command help subcommand
10091     * </pre><p>
10092     * When invoked without additional parameters, it prints usage help for the parent command. For example:
10093     * </p><pre>
10094     *
10095     * // print help for command
10096     * command help
10097     * </pre>
10098     * For {@linkplain Messages internationalization}: this command has a {@code --help} option with {@code descriptionKey = "helpCommand.help"},
10099     * and a {@code COMMAND} positional parameter with {@code descriptionKey = "helpCommand.command"}.
10100     * @since 3.0
10101     */
10102    @Command(name = "help", header = "Displays help information about the specified command",
10103            synopsisHeading = "%nUsage: ", helpCommand = true,
10104            description = {"%nWhen no COMMAND is given, the usage help for the main command is displayed.",
10105                    "If a COMMAND is specified, the help for that command is shown.%n"})
10106    public static final class HelpCommand implements IHelpCommandInitializable, Runnable {
10107
10108        @Option(names = {"-h", "--help"}, usageHelp = true, descriptionKey = "helpCommand.help",
10109                description = "Show usage help for the help command and exit.")
10110        private boolean helpRequested;
10111
10112        @Parameters(paramLabel = "COMMAND", descriptionKey = "helpCommand.command",
10113                    description = "The COMMAND to display the usage help message for.")
10114        private String[] commands = new String[0];
10115
10116        private CommandLine self;
10117        private PrintStream out;
10118        private PrintStream err;
10119        private Help.Ansi ansi;
10120
10121        /** Invokes {@link #usage(PrintStream, Help.Ansi) usage} for the specified command, or for the parent command. */
10122        public void run() {
10123            CommandLine parent = self == null ? null : self.getParent();
10124            if (parent == null) { return; }
10125            if (commands.length > 0) {
10126                CommandLine subcommand = parent.getSubcommands().get(commands[0]);
10127                if (subcommand != null) {
10128                    subcommand.usage(out, ansi);
10129                } else {
10130                    throw new ParameterException(parent, "Unknown subcommand '" + commands[0] + "'.", null, commands[0]);
10131                }
10132            } else {
10133                parent.usage(out, ansi);
10134            }
10135        }
10136        /** {@inheritDoc} */
10137        public void init(CommandLine helpCommandLine, Help.Ansi ansi, PrintStream out, PrintStream err) {
10138            this.self = Assert.notNull(helpCommandLine, "helpCommandLine");
10139            this.ansi = Assert.notNull(ansi, "ansi");
10140            this.out  = Assert.notNull(out, "out");
10141            this.err  = Assert.notNull(err, "err");
10142        }
10143    }
10144
10145    /** Help commands that provide usage help for other commands can implement this interface to be initialized with the information they need.
10146     * <p>The {@link #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi) CommandLine::printHelpIfRequested} method calls the
10147     * {@link #init(CommandLine, picocli.CommandLine.Help.Ansi, PrintStream, PrintStream) init} method on commands marked as {@link Command#helpCommand() helpCommand}
10148     * before the help command's {@code run} or {@code call} method is called.</p>
10149     * <p><b>Implementation note:</b></p><p>
10150     * If an error occurs in the {@code run} or {@code call} method while processing the help request, it is recommended custom Help
10151     * commands throw a {@link ParameterException ParameterException} with a reference to the parent command. The {@link DefaultExceptionHandler DefaultExceptionHandler} will print
10152     * 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.
10153     * </p>
10154     * @since 3.0 */
10155    public static interface IHelpCommandInitializable {
10156        /** Initializes this object with the information needed to implement a help command that provides usage help for other commands.
10157         * @param helpCommandLine the {@code CommandLine} object associated with this help command. Implementors can use
10158         *                        this to walk the command hierarchy and get access to the help command's parent and sibling commands.
10159         * @param ansi whether to use Ansi colors or not
10160         * @param out the stream to print the usage help message to
10161         * @param err the error stream to print any diagnostic messages to, in addition to the output from the exception handler
10162         */
10163        void init(CommandLine helpCommandLine, Help.Ansi ansi, PrintStream out, PrintStream err);
10164    }
10165
10166    /**
10167     * Renders a section of the usage help message. The usage help message can be customized:
10168     * use the {@link #setHelpSectionKeys(List)} and {@link #setHelpSectionMap(Map)} to change the order of sections,
10169     * delete standard sections, add custom sections or replace the renderer of a standard sections with a custom one.
10170     * <p>
10171     * This gives complete freedom on how a usage help message section is rendered, but it also means that the section renderer
10172     * is responsible for all aspects of rendering the section, including layout and emitting ANSI escape codes.
10173     * 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.
10174     * </p>
10175     * @see UsageMessageSpec
10176     * @since 3.9
10177     */
10178    public interface IHelpSectionRenderer {
10179        /**
10180         * Renders a section of the usage help, like header heading, header, synopsis heading,
10181         * synopsis, description heading, description, etc.
10182         * @param help the {@code Help} instance for which to render a section
10183         * @return the text for this section; may contain {@linkplain Help.Ansi ANSI} escape codes
10184         * @since 3.9
10185         */
10186        String render(Help help);
10187    }
10188
10189    /**
10190     * A collection of methods and inner classes that provide fine-grained control over the contents and layout of
10191     * the usage help message to display to end users when help is requested or invalid input values were specified.
10192     * <h2>Class Diagram of the CommandLine.Help API</h2>
10193     * <p>
10194     * <img src="doc-files/class-diagram-help-api.png" alt="Class Diagram of the CommandLine.Help API">
10195     * </p>
10196     * <h2>Layered API</h2>
10197     * <p>The {@link Command} annotation and the {@link UsageMessageSpec} programmatic API equivalent
10198     * provide the easiest way to configure the usage help message. See
10199     * the <a href="https://remkop.github.io/picocli/index.html#_usage_help">Manual</a> for details.</p>
10200     * <p>This Help class provides high-level functions to create sections of the usage help message and headings
10201     * for these sections. Instead of calling the {@link CommandLine#usage(PrintStream, CommandLine.Help.ColorScheme)}
10202     * method, application authors may want to create a custom usage help message by reorganizing sections in a
10203     * different order and/or adding custom sections.</p>
10204     * <p>Finally, the Help class contains inner classes and interfaces that can be used to create custom help messages.</p>
10205     * <h3>IOptionRenderer and IParameterRenderer</h3>
10206     * <p>Renders a field annotated with {@link Option} or {@link Parameters} to an array of {@link Text} values.
10207     * By default, these values are</p><ul>
10208     * <li>mandatory marker character (if the option/parameter is {@link Option#required() required})</li>
10209     * <li>short option name (empty for parameters)</li>
10210     * <li>comma or empty (empty for parameters)</li>
10211     * <li>long option names (the parameter {@link IParamLabelRenderer label} for parameters)</li>
10212     * <li>description</li>
10213     * </ul>
10214     * <p>Other components rely on this ordering.</p>
10215     * <h3>Layout</h3>
10216     * <p>Delegates to the renderers to create {@link Text} values for the annotated fields, and uses a
10217     * {@link TextTable} to display these values in tabular format. Layout is responsible for deciding which values
10218     * to display where in the table. By default, Layout shows one option or parameter per table row.</p>
10219     * <h3>TextTable</h3>
10220     * <p>Responsible for spacing out {@link Text} values according to the {@link Column} definitions the table was
10221     * created with. Columns have a width, indentation, and an overflow policy that decides what to do if a value is
10222     * longer than the column's width.</p>
10223     * <h3>Text</h3>
10224     * <p>Encapsulates rich text with styles and colors in a way that other components like {@link TextTable} are
10225     * unaware of the embedded ANSI escape codes.</p>
10226     */
10227    public static class Help {
10228
10229        /** Constant String holding the default program name, value defined in {@link CommandSpec#DEFAULT_COMMAND_NAME}. */
10230        protected static final String DEFAULT_COMMAND_NAME = CommandSpec.DEFAULT_COMMAND_NAME;
10231
10232        /** Constant String holding the default string that separates options from option parameters, value defined in {@link ParserSpec#DEFAULT_SEPARATOR}. */
10233        protected static final String DEFAULT_SEPARATOR = ParserSpec.DEFAULT_SEPARATOR;
10234
10235        private final static int defaultOptionsColumnWidth = 24;
10236        private final CommandSpec commandSpec;
10237        private final ColorScheme colorScheme;
10238        private final Map<String, Help> commands = new LinkedHashMap<String, Help>();
10239        private List<String> aliases = Collections.emptyList();
10240
10241        private IParamLabelRenderer parameterLabelRenderer;
10242
10243        /** Constructs a new {@code Help} instance with a default color scheme, initialized from annotatations
10244         * on the specified class and superclasses.
10245         * @param command the annotated object to create usage help for */
10246        public Help(Object command) {
10247            this(command, Ansi.AUTO);
10248        }
10249
10250        /** Constructs a new {@code Help} instance with a default color scheme, initialized from annotatations
10251         * on the specified class and superclasses.
10252         * @param command the annotated object to create usage help for
10253         * @param ansi whether to emit ANSI escape codes or not */
10254        public Help(Object command, Ansi ansi) {
10255            this(command, defaultColorScheme(ansi));
10256        }
10257        /** Constructs a new {@code Help} instance with the specified color scheme, initialized from annotatations
10258         * on the specified class and superclasses.
10259         * @param command the annotated object to create usage help for
10260         * @param colorScheme the color scheme to use
10261         * @deprecated use {@link picocli.CommandLine.Help#Help(picocli.CommandLine.Model.CommandSpec, picocli.CommandLine.Help.ColorScheme)}  */
10262        @Deprecated public Help(Object command, ColorScheme colorScheme) {
10263            this(CommandSpec.forAnnotatedObject(command, new DefaultFactory()), colorScheme);
10264        }
10265        /** Constructs a new {@code Help} instance with the specified color scheme, initialized from annotatations
10266         * on the specified class and superclasses.
10267         * @param commandSpec the command model to create usage help for
10268         * @param colorScheme the color scheme to use */
10269        public Help(CommandSpec commandSpec, ColorScheme colorScheme) {
10270            this.commandSpec = Assert.notNull(commandSpec, "commandSpec");
10271            this.aliases = new ArrayList<String>(Arrays.asList(commandSpec.aliases()));
10272            this.aliases.add(0, commandSpec.name());
10273            this.colorScheme = Assert.notNull(colorScheme, "colorScheme").applySystemProperties();
10274            parameterLabelRenderer = createDefaultParamLabelRenderer(); // uses help separator
10275
10276            this.addAllSubcommands(commandSpec.subcommands());
10277        }
10278
10279        Help withCommandNames(List<String> aliases) { this.aliases = aliases; return this; }
10280
10281        /** Returns the {@code CommandSpec} model that this Help was constructed with.
10282         * @since 3.9 */
10283        public CommandSpec commandSpec() { return commandSpec; }
10284
10285        /** Returns the {@code ColorScheme} model that this Help was constructed with.
10286         * @since 3.0 */
10287        public ColorScheme colorScheme() { return colorScheme; }
10288
10289        /** Returns the {@code IHelpFactory} that this Help was constructed with.
10290         * @since 3.9 */
10291        private IHelpFactory getHelpFactory() { return commandSpec.usageMessage().helpFactory(); }
10292
10293        /** Returns the map of subcommand {@code Help} instances for this command Help.
10294         * @since 3.9 */
10295        protected Map<String, Help> subcommands() { return Collections.unmodifiableMap(commands); }
10296
10297        /** Returns the list of aliases for the command in this Help.
10298         * @since 3.9 */
10299        protected List<String> aliases() { return Collections.unmodifiableList(aliases); }
10300
10301        /** Option and positional parameter value label renderer used for the synopsis line(s) and the option list.
10302         * By default initialized to the result of {@link #createDefaultParamLabelRenderer()}, which takes a snapshot
10303         * of the {@link ParserSpec#separator()} at construction time. If the separator is modified after Help construction, you
10304         * may need to re-initialize this field by calling {@link #createDefaultParamLabelRenderer()} again. */
10305        public IParamLabelRenderer parameterLabelRenderer() {return parameterLabelRenderer;}
10306
10307        /** Registers all specified subcommands with this Help.
10308         * @param commands maps the command names to the associated CommandLine object
10309         * @return this Help instance (for method chaining)
10310         * @see CommandLine#getSubcommands()
10311         */
10312        public Help addAllSubcommands(Map<String, CommandLine> commands) {
10313            if (commands != null) {
10314                // first collect aliases
10315                Map<CommandLine, List<String>> done = new IdentityHashMap<CommandLine, List<String>>();
10316                for (CommandLine cmd : commands.values()) {
10317                    if (!done.containsKey(cmd)) {
10318                        done.put(cmd, new ArrayList<String>(Arrays.asList(cmd.commandSpec.aliases())));
10319                    }
10320                }
10321                // 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)
10322                for (Map.Entry<String, CommandLine> entry : commands.entrySet()) {
10323                    List<String> aliases = done.get(entry.getValue());
10324                    if (!aliases.contains(entry.getKey())) { aliases.add(0, entry.getKey()); }
10325                }
10326                // The aliases list for each command now has at least one entry, with the main name at the front.
10327                // Now we loop over the commands in the order that they were registered on their parent command.
10328                for (Map.Entry<String, CommandLine> entry : commands.entrySet()) {
10329                    // not registering hidden commands is easier than suppressing display in Help.commandList():
10330                    // if all subcommands are hidden, help should not show command list header
10331                    if (!entry.getValue().getCommandSpec().usageMessage().hidden()) {
10332                        List<String> aliases = done.remove(entry.getValue());
10333                        if (aliases != null) { // otherwise we already processed this command by another alias
10334                            addSubcommand(aliases, entry.getValue());
10335                        }
10336                    }
10337                }
10338            }
10339            return this;
10340        }
10341
10342        /** Registers the specified subcommand with this Help.
10343         * @param commandNames the name and aliases of the subcommand to display in the usage message
10344         * @param commandLine the {@code CommandLine} object to get more information from
10345         * @return this Help instance (for method chaining) */
10346        Help addSubcommand(List<String> commandNames, CommandLine commandLine) {
10347            String all = commandNames.toString();
10348            commands.put(all.substring(1, all.length() - 1), getHelpFactory().create(commandLine.commandSpec, colorScheme).withCommandNames(commandNames));
10349            return this;
10350        }
10351
10352        /** Registers the specified subcommand with this Help.
10353         * @param commandName the name of the subcommand to display in the usage message
10354         * @param command the {@code CommandSpec} or {@code @Command} annotated object to get more information from
10355         * @return this Help instance (for method chaining)
10356         * @deprecated
10357         */
10358        @Deprecated public Help addSubcommand(String commandName, Object command) {
10359            commands.put(commandName,
10360                    getHelpFactory().create(CommandSpec.forAnnotatedObject(command, commandSpec.commandLine().factory), defaultColorScheme(Ansi.AUTO)));
10361            return this;
10362        }
10363
10364        List<OptionSpec> options() { return commandSpec.options(); }
10365        List<PositionalParamSpec> positionalParameters() { return commandSpec.positionalParameters(); }
10366        String commandName() { return commandSpec.name(); }
10367
10368        /** Returns a synopsis for the command without reserving space for the synopsis heading.
10369         * @return a synopsis
10370         * @see #abbreviatedSynopsis()
10371         * @see #detailedSynopsis(Comparator, boolean)
10372         * @deprecated use {@link #synopsis(int)} instead
10373         */
10374        @Deprecated public String synopsis() { return synopsis(0); }
10375
10376        /**
10377         * Returns a synopsis for the command, reserving the specified space for the synopsis heading.
10378         * @param synopsisHeadingLength the length of the synopsis heading that will be displayed on the same line
10379         * @return a synopsis
10380         * @see #abbreviatedSynopsis()
10381         * @see #detailedSynopsis(Comparator, boolean)
10382         * @see #synopsisHeading
10383         */
10384        public String synopsis(int synopsisHeadingLength) {
10385            if (!empty(commandSpec.usageMessage().customSynopsis())) { return customSynopsis(); }
10386            return commandSpec.usageMessage().abbreviateSynopsis() ? abbreviatedSynopsis()
10387                    : detailedSynopsis(synopsisHeadingLength, createShortOptionArityAndNameComparator(), true);
10388        }
10389
10390        /** Generates a generic synopsis like {@code <command name> [OPTIONS] [PARAM1 [PARAM2]...]}, omitting parts
10391         * that don't apply to the command (e.g., does not show [OPTIONS] if the command has no options).
10392         * @return a generic synopsis */
10393        public String abbreviatedSynopsis() {
10394            StringBuilder sb = new StringBuilder();
10395            if (!commandSpec.optionsMap().isEmpty()) { // only show if annotated object actually has options
10396                sb.append(" [OPTIONS]");
10397            }
10398            // sb.append(" [--] "); // implied
10399            for (PositionalParamSpec positionalParam : commandSpec.positionalParameters()) {
10400                if (!positionalParam.hidden()) {
10401                    sb.append(' ').append(parameterLabelRenderer().renderParameterLabel(positionalParam, ansi(), colorScheme.parameterStyles));
10402                }
10403            }
10404
10405            // only show if object has subcommands
10406            if (!commandSpec.subcommands().isEmpty()) {
10407                sb.append(" [COMMAND]");
10408            }
10409
10410            return colorScheme.commandText(commandSpec.qualifiedName()).toString()
10411                    + (sb.toString()) + System.getProperty("line.separator");
10412        }
10413        /** Generates a detailed synopsis message showing all options and parameters. Follows the unix convention of
10414         * showing optional options and parameters in square brackets ({@code [ ]}).
10415         * @param optionSort comparator to sort options or {@code null} if options should not be sorted
10416         * @param clusterBooleanOptions {@code true} if boolean short options should be clustered into a single string
10417         * @return a detailed synopsis
10418         * @deprecated use {@link #detailedSynopsis(int, Comparator, boolean)} instead. */
10419        @Deprecated public String detailedSynopsis(Comparator<OptionSpec> optionSort, boolean clusterBooleanOptions) {
10420            return detailedSynopsis(0, optionSort, clusterBooleanOptions);
10421        }
10422
10423        /** Generates a detailed synopsis message showing all options and parameters. Follows the unix convention of
10424         * showing optional options and parameters in square brackets ({@code [ ]}).
10425         * @param synopsisHeadingLength the length of the synopsis heading that will be displayed on the same line
10426         * @param optionSort comparator to sort options or {@code null} if options should not be sorted
10427         * @param clusterBooleanOptions {@code true} if boolean short options should be clustered into a single string
10428         * @return a detailed synopsis
10429         * @since 3.0 */
10430        public String detailedSynopsis(int synopsisHeadingLength, Comparator<OptionSpec> optionSort, boolean clusterBooleanOptions) {
10431            Set<ArgSpec> argsInGroups = new HashSet<ArgSpec>();
10432            Text groupsText = createDetailedSynopsisGroupsText(argsInGroups);
10433            Text optionText = createDetailedSynopsisOptionsText(argsInGroups, optionSort, clusterBooleanOptions);
10434            Text positionalParamText = createDetailedSynopsisPositionalsText(argsInGroups);
10435            Text commandText = createDetailedSynopsisCommandText();
10436
10437            Text text = groupsText.concat(optionText).concat(positionalParamText).concat(commandText);
10438
10439            return insertSynopsisCommandName(synopsisHeadingLength, text);
10440        }
10441
10442        /** Returns a Text object containing a partial detailed synopsis showing only the options and positional parameters in
10443         * the specified {@linkplain ArgGroup#validate() validating} {@linkplain ArgGroup groups}, starting with a {@code " "} space.
10444         * @param outparam_groupArgs all options and positional parameters in the groups this method generates a synopsis for;
10445         *                           these options and positional parameters should be excluded from appearing elsewhere in the synopsis
10446         * @return the formatted groups synopsis elements, starting with a {@code " "} space, or an empty Text if this command has no validating groups
10447         * @since 4.0 */
10448        protected Text createDetailedSynopsisGroupsText(Set<ArgSpec> outparam_groupArgs) {
10449            Set<ArgGroupSpec> remove = new HashSet<ArgGroupSpec>();
10450            List<ArgGroupSpec> groups = new ArrayList<ArgGroupSpec>(commandSpec().argGroups());
10451            for (ArgGroupSpec group : groups) {
10452                if (group.validate()) {
10453                    // remove subgroups
10454                    remove.addAll(group.subgroups());
10455
10456                    // exclude options and positional parameters in this group
10457                    outparam_groupArgs.addAll(group.args());
10458
10459                    // exclude options and positional parameters in the subgroups
10460                    for (ArgGroupSpec subgroup : group.subgroups()) {
10461                        outparam_groupArgs.addAll(subgroup.args());
10462                    }
10463                } else {
10464                    remove.add(group); // non-validating groups should not impact synopsis
10465                }
10466            }
10467            groups.removeAll(remove);
10468            Text groupText = ansi().new Text(0);
10469            for (ArgGroupSpec group : groups) {
10470                groupText = groupText.concat(" ").concat(group.synopsisText(colorScheme()));
10471            }
10472            return groupText;
10473        }
10474        /** Returns a Text object containing a partial detailed synopsis showing only the options, starting with a {@code " "} space.
10475         * Follows the unix convention of showing optional options and parameters in square brackets ({@code [ ]}).
10476         * @param done the list of options and positional parameters for which a synopsis was already generated. Options in this set should be excluded.
10477         * @param optionSort comparator to sort options or {@code null} if options should not be sorted
10478         * @param clusterBooleanOptions {@code true} if boolean short options should be clustered into a single string
10479         * @return the formatted options, starting with a {@code " "} space, or an empty Text if this command has no named options
10480         * @since 3.9 */
10481        protected Text createDetailedSynopsisOptionsText(Collection<ArgSpec> done, Comparator<OptionSpec> optionSort, boolean clusterBooleanOptions) {
10482            Text optionText = ansi().new Text(0);
10483            List<OptionSpec> options = new ArrayList<OptionSpec>(commandSpec.options()); // iterate in declaration order
10484            if (optionSort != null) {
10485                Collections.sort(options, optionSort);// iterate in specified sort order
10486            }
10487            options.removeAll(done);
10488            if (clusterBooleanOptions) { // cluster all short boolean options into a single string
10489                List<OptionSpec> booleanOptions = new ArrayList<OptionSpec>();
10490                StringBuilder clusteredRequired = new StringBuilder("-");
10491                StringBuilder clusteredOptional = new StringBuilder("-");
10492                for (OptionSpec option : options) {
10493                    if (option.hidden()) { continue; }
10494                    boolean isFlagOption = option.typeInfo().isBoolean();
10495                    if (isFlagOption && option.arity().max <= 0) { // #612 consider arity: boolean options may require a parameter
10496                        String shortestName = option.shortestName();
10497                        if (shortestName.length() == 2 && shortestName.startsWith("-")) {
10498                            booleanOptions.add(option);
10499                            if (option.required()) {
10500                                clusteredRequired.append(shortestName.substring(1));
10501                            } else {
10502                                clusteredOptional.append(shortestName.substring(1));
10503                            }
10504                        }
10505                    }
10506                }
10507                options.removeAll(booleanOptions);
10508                if (clusteredRequired.length() > 1) { // initial length was 1
10509                    optionText = optionText.concat(" ").concat(colorScheme.optionText(clusteredRequired.toString()));
10510                }
10511                if (clusteredOptional.length() > 1) { // initial length was 1
10512                    optionText = optionText.concat(" [").concat(colorScheme.optionText(clusteredOptional.toString())).concat("]");
10513                }
10514            }
10515            for (OptionSpec option : options) {
10516                if (!option.hidden()) {
10517                    Text name = colorScheme.optionText(option.shortestName());
10518                    Text param = parameterLabelRenderer().renderParameterLabel(option, colorScheme.ansi(), colorScheme.optionParamStyles);
10519                    if (option.required()) { // e.g., -x=VAL
10520                        optionText = optionText.concat(" ").concat(name).concat(param).concat("");
10521                        if (option.isMultiValue()) { // e.g., -x=VAL [-x=VAL]...
10522                            optionText = optionText.concat(" [").concat(name).concat(param).concat("]...");
10523                        }
10524                    } else {
10525                        optionText = optionText.concat(" [").concat(name).concat(param).concat("]");
10526                        if (option.isMultiValue()) { // add ellipsis to show option is repeatable
10527                            optionText = optionText.concat("...");
10528                        }
10529                    }
10530                }
10531            }
10532            return optionText;
10533        }
10534
10535        /** Returns a Text object containing a partial detailed synopsis showing only the positional parameters, starting with a {@code " "} space.
10536         * Follows the unix convention of showing optional options and parameters in square brackets ({@code [ ]}).
10537         * @param done the list of options and positional parameters for which a synopsis was already generated. Positional parameters in this set should be excluded.
10538         * @return the formatted positional parameters, starting with a {@code " "} space, or an empty Text if this command has no positional parameters
10539         * @since 3.9 */
10540        protected Text createDetailedSynopsisPositionalsText(Collection<ArgSpec> done) {
10541            Text positionalParamText = ansi().new Text(0);
10542            List<PositionalParamSpec> positionals = new ArrayList<PositionalParamSpec>(commandSpec.positionalParameters()); // iterate in declaration order
10543            positionals.removeAll(done);
10544            for (PositionalParamSpec positionalParam : positionals) {
10545                if (!positionalParam.hidden()) {
10546                    positionalParamText = positionalParamText.concat(" ");
10547                    Text label = parameterLabelRenderer().renderParameterLabel(positionalParam, colorScheme.ansi(), colorScheme.parameterStyles);
10548                    positionalParamText = positionalParamText.concat(label);
10549                }
10550            }
10551            return positionalParamText;
10552        }
10553
10554        /** Returns a Text object containing a partial detailed synopsis showing only the subcommands, starting with a {@code " "} space.
10555         * Follows the unix convention of showing optional elements in square brackets ({@code [ ]}).
10556         * @return this implementation returns a hard-coded string {@code " [COMMAND]"} if this command has subcommands, an empty Text otherwise
10557         * @since 3.9 */
10558        protected Text createDetailedSynopsisCommandText() {
10559            Text commandText = ansi().new Text(0);
10560            if (!commandSpec.subcommands().isEmpty()){
10561                commandText = commandText.concat(" [")
10562                        .concat("COMMAND")
10563                        .concat("]");
10564            }
10565            return commandText;
10566        }
10567
10568        /**
10569         * Returns the detailed synopsis text by inserting the command name before the specified text with options and positional parameters details.
10570         * @param synopsisHeadingLength length of the synopsis heading string to be displayed on the same line as the first synopsis line.
10571         *                              For example, if the synopsis heading is {@code "Usage: "}, this value is 7.
10572         * @param optionsAndPositionalsAndCommandsDetails formatted string with options, positional parameters and subcommands.
10573         *          Follows the unix convention of showing optional options and parameters in square brackets ({@code [ ]}).
10574         * @return the detailed synopsis text, in multiple lines if the length exceeds the usage width
10575         */
10576        protected String insertSynopsisCommandName(int synopsisHeadingLength, Text optionsAndPositionalsAndCommandsDetails) {
10577            // Fix for #142: first line of synopsis overshoots max. characters
10578            String commandName = commandSpec.qualifiedName();
10579            int firstColumnLength = commandName.length() + synopsisHeadingLength;
10580
10581            // synopsis heading ("Usage: ") may be on the same line, so adjust column width
10582            TextTable textTable = TextTable.forColumnWidths(ansi(), firstColumnLength, width() - firstColumnLength);
10583            textTable.indentWrappedLines = 1; // don't worry about first line: options (2nd column) always start with a space
10584
10585            // right-adjust the command name by length of synopsis heading
10586            Text PADDING = Ansi.OFF.new Text(stringOf('X', synopsisHeadingLength));
10587            textTable.addRowValues(PADDING.concat(colorScheme.commandText(commandName)), optionsAndPositionalsAndCommandsDetails);
10588            return textTable.toString().substring(synopsisHeadingLength); // cut off leading synopsis heading spaces
10589        }
10590
10591        /** Returns the number of characters the synopsis heading will take on the same line as the synopsis.
10592         * @return the number of characters the synopsis heading will take on the same line as the synopsis.
10593         * @see #detailedSynopsis(int, Comparator, boolean)
10594         */
10595        public int synopsisHeadingLength() {
10596            String[] lines = Ansi.OFF.new Text(commandSpec.usageMessage().synopsisHeading()).toString().split("\\r?\\n|\\r|%n", -1);
10597            return lines[lines.length - 1].length();
10598        }
10599        /**
10600         * <p>Returns a description of the {@linkplain Option options} supported by the application.
10601         * This implementation {@linkplain #createShortOptionNameComparator() sorts options alphabetically}, and shows
10602         * only the {@linkplain Option#hidden() non-hidden} options in a {@linkplain TextTable tabular format}
10603         * using the {@linkplain #createDefaultOptionRenderer() default renderer} and {@linkplain Layout default layout}.</p>
10604         * @return the fully formatted option list
10605         * @see #optionList(Layout, Comparator, IParamLabelRenderer)
10606         */
10607        public String optionList() {
10608            Comparator<OptionSpec> sortOrder = commandSpec.usageMessage().sortOptions()
10609                    ? createShortOptionNameComparator()
10610                    : createOrderComparatorIfNecessary(commandSpec.options());
10611
10612            return optionList(createLayout(calcLongOptionColumnWidth()), sortOrder, parameterLabelRenderer());
10613        }
10614
10615        private static Comparator<OptionSpec> createOrderComparatorIfNecessary(List<OptionSpec> options) {
10616            for (OptionSpec option : options) { if (option.order() != OptionSpec.DEFAULT_ORDER) { return createOrderComparator(); } }
10617            return null;
10618        }
10619
10620        private int calcLongOptionColumnWidth() {
10621            int max = 0;
10622            IOptionRenderer optionRenderer = new DefaultOptionRenderer(false, " ");
10623            for (OptionSpec option : commandSpec.options()) {
10624                Text[][] values = optionRenderer.render(option, parameterLabelRenderer(), colorScheme);
10625                int len = values[0][3].length;
10626                if (len < Help.defaultOptionsColumnWidth - 3) { max = Math.max(max, len); }
10627            }
10628            IParameterRenderer paramRenderer = new DefaultParameterRenderer(false, " ");
10629            for (PositionalParamSpec positional : commandSpec.positionalParameters()) {
10630                Text[][] values = paramRenderer.render(positional, parameterLabelRenderer(), colorScheme);
10631                int len = values[0][3].length;
10632                if (len < Help.defaultOptionsColumnWidth - 3) { max = Math.max(max, len); }
10633            }
10634            return max + 3;
10635        }
10636
10637        /** Sorts all {@code Options} with the specified {@code comparator} (if the comparator is non-{@code null}),
10638         * then {@linkplain Layout#addOption(CommandLine.Model.OptionSpec, CommandLine.Help.IParamLabelRenderer) adds} all non-hidden options to the
10639         * specified TextTable and returns the result of TextTable.toString().
10640         * @param layout responsible for rendering the option list
10641         * @param valueLabelRenderer used for options with a parameter
10642         * @return the fully formatted option list
10643         * @since 3.0 */
10644        public String optionList(Layout layout, Comparator<OptionSpec> optionSort, IParamLabelRenderer valueLabelRenderer) {
10645            List<OptionSpec> options = new ArrayList<OptionSpec>(commandSpec.options()); // options are stored in order of declaration
10646            if (optionSort != null) {
10647                Collections.sort(options, optionSort); // default: sort options ABC
10648            }
10649            List<ArgGroupSpec> groups = optionListGroups();
10650            for (ArgGroupSpec group : groups) { options.removeAll(group.options()); }
10651
10652            StringBuilder sb = new StringBuilder();
10653            layout.addOptions(options, valueLabelRenderer);
10654            sb.append(layout.toString());
10655
10656            int longOptionColumnWidth = calcLongOptionColumnWidth();
10657            Collections.sort(groups, new SortByOrder<ArgGroupSpec>());
10658            for (ArgGroupSpec group : groups) {
10659                sb.append(heading(ansi(), width(), group.heading()));
10660
10661                Layout groupLayout = createLayout(longOptionColumnWidth);
10662                groupLayout.addPositionalParameters(group.positionalParameters(), valueLabelRenderer);
10663                List<OptionSpec> groupOptions = new ArrayList<OptionSpec>(group.options());
10664                if (optionSort != null) {
10665                    Collections.sort(groupOptions, optionSort);
10666                }
10667                groupLayout.addOptions(groupOptions, valueLabelRenderer);
10668                sb.append(groupLayout);
10669            }
10670            return sb.toString();
10671        }
10672
10673        /** Returns the list of {@code ArgGroupSpec}s with a non-{@code null} heading. */
10674        private List<ArgGroupSpec> optionListGroups() {
10675            List<ArgGroupSpec> result = new ArrayList<ArgGroupSpec>();
10676            optionListGroups(commandSpec.argGroups(), result);
10677            return result;
10678        }
10679        private static void optionListGroups(List<ArgGroupSpec> groups, List<ArgGroupSpec> result) {
10680            for (ArgGroupSpec group : groups) {
10681                optionListGroups(group.subgroups(), result);
10682                if (group.heading() != null) { result.add(group); }
10683            }
10684        }
10685
10686        /**
10687         * Returns the section of the usage help message that lists the parameters with their descriptions.
10688         * @return the section of the usage help message that lists the parameters
10689         */
10690        public String parameterList() {
10691            return parameterList(createLayout(calcLongOptionColumnWidth()), parameterLabelRenderer());
10692        }
10693        /**
10694         * Returns the section of the usage help message that lists the parameters with their descriptions.
10695         * @param layout the layout to use
10696         * @param paramLabelRenderer for rendering parameter names
10697         * @return the section of the usage help message that lists the parameters
10698         */
10699        public String parameterList(Layout layout, IParamLabelRenderer paramLabelRenderer) {
10700            List<PositionalParamSpec> positionals = new ArrayList<PositionalParamSpec>(commandSpec.positionalParameters());
10701            List<ArgGroupSpec> groups = optionListGroups();
10702            for (ArgGroupSpec group : groups) { positionals.removeAll(group.positionalParameters()); }
10703
10704            layout.addPositionalParameters(positionals, paramLabelRenderer);
10705            return layout.toString();
10706        }
10707
10708        private static String heading(Ansi ansi, int usageWidth, String values, Object... params) {
10709            StringBuilder sb = join(ansi, usageWidth, new String[] {values}, new StringBuilder(), params);
10710            return trimLineSeparator(sb.toString()) + new String(spaces(countTrailingSpaces(values)));
10711        }
10712        static String trimLineSeparator(String result) {
10713            return result.endsWith(System.getProperty("line.separator"))
10714                    ? result.substring(0, result.length() - System.getProperty("line.separator").length()) : result;
10715        }
10716
10717        private static char[] spaces(int length) { char[] result = new char[length]; Arrays.fill(result, ' '); return result; }
10718        private static int countTrailingSpaces(String str) {
10719            if (str == null) {return 0;}
10720            int trailingSpaces = 0;
10721            for (int i = str.length() - 1; i >= 0 && str.charAt(i) == ' '; i--) { trailingSpaces++; }
10722            return trailingSpaces;
10723        }
10724
10725        /** Formats each of the specified values and appends it to the specified StringBuilder.
10726         * @param ansi whether the result should contain ANSI escape codes or not
10727         * @param usageHelpWidth the width of the usage help message
10728         * @param values the values to format and append to the StringBuilder
10729         * @param sb the StringBuilder to collect the formatted strings
10730         * @param params the parameters to pass to the format method when formatting each value
10731         * @return the specified StringBuilder */
10732        public static StringBuilder join(Ansi ansi, int usageHelpWidth, String[] values, StringBuilder sb, Object... params) {
10733            if (values != null) {
10734                TextTable table = TextTable.forColumnWidths(ansi, usageHelpWidth);
10735                table.indentWrappedLines = 0;
10736                for (String summaryLine : values) {
10737                    Text[] lines = ansi.new Text(format(summaryLine, params)).splitLines();
10738                    for (Text line : lines) {  table.addRowValues(line); }
10739                }
10740                table.toString(sb);
10741            }
10742            return sb;
10743        }
10744        private int width() { return commandSpec.usageMessage().width(); }
10745        /** Returns command custom synopsis as a string. A custom synopsis can be zero or more lines, and can be
10746         * specified declaratively with the {@link Command#customSynopsis()} annotation attribute or programmatically
10747         * by setting the Help instance's {@link Help#customSynopsis} field.
10748         * @param params Arguments referenced by the format specifiers in the synopsis strings
10749         * @return the custom synopsis lines combined into a single String (which may be empty)
10750         */
10751        public String customSynopsis(Object... params) {
10752            return join(ansi(), width(), commandSpec.usageMessage().customSynopsis(), new StringBuilder(), params).toString();
10753        }
10754        /** Returns command description text as a string. Description text can be zero or more lines, and can be specified
10755         * declaratively with the {@link Command#description()} annotation attribute or programmatically by
10756         * setting the Help instance's {@link Help#description} field.
10757         * @param params Arguments referenced by the format specifiers in the description strings
10758         * @return the description lines combined into a single String (which may be empty)
10759         */
10760        public String description(Object... params) {
10761            return join(ansi(), width(), commandSpec.usageMessage().description(), new StringBuilder(), params).toString();
10762        }
10763        /** Returns the command header text as a string. Header text can be zero or more lines, and can be specified
10764         * declaratively with the {@link Command#header()} annotation attribute or programmatically by
10765         * setting the Help instance's {@link Help#header} field.
10766         * @param params Arguments referenced by the format specifiers in the header strings
10767         * @return the header lines combined into a single String (which may be empty)
10768         */
10769        public String header(Object... params) {
10770            return join(ansi(), width(), commandSpec.usageMessage().header(), new StringBuilder(), params).toString();
10771        }
10772        /** Returns command footer text as a string. Footer text can be zero or more lines, and can be specified
10773         * declaratively with the {@link Command#footer()} annotation attribute or programmatically by
10774         * setting the Help instance's {@link Help#footer} field.
10775         * @param params Arguments referenced by the format specifiers in the footer strings
10776         * @return the footer lines combined into a single String (which may be empty)
10777         */
10778        public String footer(Object... params) {
10779            return join(ansi(), width(), commandSpec.usageMessage().footer(), new StringBuilder(), params).toString();
10780        }
10781
10782        /** Returns the text displayed before the header text; the result of {@code String.format(headerHeading, params)}.
10783         * @param params the parameters to use to format the header heading
10784         * @return the formatted header heading */
10785        public String headerHeading(Object... params) {
10786            return heading(ansi(), width(), commandSpec.usageMessage().headerHeading(), params);
10787        }
10788
10789        /** Returns the text displayed before the synopsis text; the result of {@code String.format(synopsisHeading, params)}.
10790         * @param params the parameters to use to format the synopsis heading
10791         * @return the formatted synopsis heading */
10792        public String synopsisHeading(Object... params) {
10793            return heading(ansi(), width(), commandSpec.usageMessage().synopsisHeading(), params);
10794        }
10795
10796        /** Returns the text displayed before the description text; an empty string if there is no description,
10797         * otherwise the result of {@code String.format(descriptionHeading, params)}.
10798         * @param params the parameters to use to format the description heading
10799         * @return the formatted description heading */
10800        public String descriptionHeading(Object... params) {
10801            return empty(commandSpec.usageMessage().descriptionHeading()) ? "" : heading(ansi(), width(), commandSpec.usageMessage().descriptionHeading(), params);
10802        }
10803
10804        /** Returns the text displayed before the positional parameter list; an empty string if there are no positional
10805         * parameters, otherwise the result of {@code String.format(parameterListHeading, params)}.
10806         * @param params the parameters to use to format the parameter list heading
10807         * @return the formatted parameter list heading */
10808        public String parameterListHeading(Object... params) {
10809            return commandSpec.positionalParameters().isEmpty() ? "" : heading(ansi(), width(), commandSpec.usageMessage().parameterListHeading(), params);
10810        }
10811
10812        /** Returns the text displayed before the option list; an empty string if there are no options,
10813         * otherwise the result of {@code String.format(optionListHeading, params)}.
10814         * @param params the parameters to use to format the option list heading
10815         * @return the formatted option list heading */
10816        public String optionListHeading(Object... params) {
10817            return commandSpec.optionsMap().isEmpty() ? "" : heading(ansi(), width(), commandSpec.usageMessage().optionListHeading(), params);
10818        }
10819
10820        /** Returns the text displayed before the command list; an empty string if there are no commands,
10821         * otherwise the result of {@code String.format(commandListHeading, params)}.
10822         * @param params the parameters to use to format the command list heading
10823         * @return the formatted command list heading */
10824        public String commandListHeading(Object... params) {
10825            return commands.isEmpty() ? "" : heading(ansi(), width(), commandSpec.usageMessage().commandListHeading(), params);
10826        }
10827
10828        /** Returns the text displayed before the footer text; the result of {@code String.format(footerHeading, params)}.
10829         * @param params the parameters to use to format the footer heading
10830         * @return the formatted footer heading */
10831        public String footerHeading(Object... params) {
10832            return heading(ansi(), width(), commandSpec.usageMessage().footerHeading(), params);
10833        }
10834        /** Returns a 2-column list with command names and the first line of their header or (if absent) description.
10835         * @return a usage help section describing the added commands */
10836        public String commandList() {
10837            if (subcommands().isEmpty()) { return ""; }
10838            int commandLength = maxLength(subcommands().keySet());
10839            Help.TextTable textTable = Help.TextTable.forColumns(ansi(),
10840                    new Help.Column(commandLength + 2, 2, Help.Column.Overflow.SPAN),
10841                    new Help.Column(width() - (commandLength + 2), 2, Help.Column.Overflow.WRAP));
10842
10843            for (Map.Entry<String, Help> entry : subcommands().entrySet()) {
10844                Help help = entry.getValue();
10845                UsageMessageSpec usage = help.commandSpec().usageMessage();
10846                String header = !empty(usage.header())
10847                        ? usage.header()[0]
10848                        : (!empty(usage.description()) ? usage.description()[0] : "");
10849                Text[] lines = ansi().text(format(header)).splitLines();
10850                for (int i = 0; i < lines.length; i++) {
10851                    textTable.addRowValues(i == 0 ? help.commandNamesText(", ") : Ansi.EMPTY_TEXT, lines[i]);
10852                }
10853            }
10854            return textTable.toString();
10855        }
10856        private static int maxLength(Collection<String> any) {
10857            List<String> strings = new ArrayList<String>(any);
10858            Collections.sort(strings, Collections.reverseOrder(Help.shortestFirst()));
10859            return strings.get(0).length();
10860        }
10861
10862        /** Returns a {@code Text} object containing the command name and all aliases, separated with the specified separator.
10863         * Command names will use the {@link ColorScheme#commandText(String) command style} for the color scheme of this Help.
10864         * @since 3.9 */
10865        public Text commandNamesText(String separator) {
10866            Text result = colorScheme().commandText(aliases().get(0));
10867            for (int i = 1; i < aliases().size(); i++) {
10868                result = result.concat(separator).concat(colorScheme().commandText(aliases().get(i)));
10869            }
10870            return result;
10871        }
10872        private static String join(String[] names, int offset, int length, String separator) {
10873            if (names == null) { return ""; }
10874            StringBuilder result = new StringBuilder();
10875            for (int i = offset; i < offset + length; i++) {
10876                result.append((i > offset) ? separator : "").append(names[i]);
10877            }
10878            return result.toString();
10879        }
10880        private static String stringOf(char chr, int length) {
10881                             char[] buff = new char[length];
10882            Arrays.fill(buff, chr);
10883            return new String(buff);
10884        }
10885
10886        /** Returns a {@code Layout} instance configured with the user preferences captured in this Help instance.
10887         * @return a Layout */
10888        public Layout createDefaultLayout() {
10889            return createLayout(Help.defaultOptionsColumnWidth);
10890        }
10891
10892        private Layout createLayout(int longOptionsColumnWidth) {
10893            return new Layout(colorScheme, TextTable.forDefaultColumns(colorScheme.ansi(), longOptionsColumnWidth, width()), createDefaultOptionRenderer(), createDefaultParameterRenderer());
10894        }
10895
10896        /** Returns a new default OptionRenderer which converts {@link OptionSpec Options} to five columns of text to match
10897         *  the default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
10898         * <ol>
10899         * <li>the required option marker</li>
10900         * <li>2-character short option name (or empty string if no short option exists)</li>
10901         * <li>comma separator (only if both short option and long option exist, empty string otherwise)</li>
10902         * <li>comma-separated string with long option name(s)</li>
10903         * <li>first element of the {@link OptionSpec#description()} array</li>
10904         * </ol>
10905         * <p>Following this, there will be one row for each of the remaining elements of the {@link
10906         *   OptionSpec#description()} array, and these rows look like {@code {"", "", "", "", option.description()[i]}}.</p>
10907         * <p>If configured, this option renderer adds an additional row to display the default field value.</p>
10908         * @return a new default OptionRenderer
10909         */
10910        public IOptionRenderer createDefaultOptionRenderer() {
10911            return new DefaultOptionRenderer(commandSpec.usageMessage.showDefaultValues(), "" +commandSpec.usageMessage().requiredOptionMarker());
10912        }
10913        /** Returns a new minimal OptionRenderer which converts {@link OptionSpec Options} to a single row with two columns
10914         * of text: an option name and a description. If multiple names or descriptions exist, the first value is used.
10915         * @return a new minimal OptionRenderer */
10916        public static IOptionRenderer createMinimalOptionRenderer() {
10917            return new MinimalOptionRenderer();
10918        }
10919
10920        /** Returns a new default ParameterRenderer which converts {@linkplain PositionalParamSpec positional parameters} to four columns of
10921         * text to match the default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
10922         * <ol>
10923         * <li>empty string </li>
10924         * <li>empty string </li>
10925         * <li>parameter(s) label as rendered by the {@link IParamLabelRenderer}</li>
10926         * <li>first element of the {@link PositionalParamSpec#description()} array</li>
10927         * </ol>
10928         * <p>Following this, there will be one row for each of the remaining elements of the {@link
10929         *   PositionalParamSpec#description()} array, and these rows look like {@code {"", "", "", param.description()[i]}}.</p>
10930         * <p>If configured, this parameter renderer adds an additional row to display the default field value.</p>
10931         * @return a new default ParameterRenderer
10932         */
10933        public IParameterRenderer createDefaultParameterRenderer() {
10934            return new DefaultParameterRenderer(commandSpec.usageMessage.showDefaultValues(), "" + commandSpec.usageMessage().requiredOptionMarker());
10935        }
10936        /** Returns a new minimal ParameterRenderer which converts {@linkplain PositionalParamSpec positional parameters}
10937         * to a single row with two columns of text: an option name and a description. If multiple descriptions exist, the first value is used.
10938         * @return a new minimal ParameterRenderer */
10939        public static IParameterRenderer createMinimalParameterRenderer() {
10940            return new MinimalParameterRenderer();
10941        }
10942
10943        /** Returns a value renderer that returns the {@code paramLabel} if defined or the field name otherwise.
10944         * @return a new minimal ParamLabelRenderer */
10945        public static IParamLabelRenderer createMinimalParamLabelRenderer() {
10946            return new IParamLabelRenderer() {
10947                public Text renderParameterLabel(ArgSpec argSpec, Ansi ansi, List<IStyle> styles) {
10948                    return ansi.apply(argSpec.paramLabel(), styles);
10949                }
10950                public String separator() { return ""; }
10951            };
10952        }
10953        /** Returns a new default param label renderer that separates option parameters from their option name
10954         * with the specified separator string, and, unless {@link ArgSpec#hideParamSyntax()} is true,
10955         * surrounds optional parameters with {@code '['} and {@code ']'}
10956         * characters and uses ellipses ("...") to indicate that any number of a parameter are allowed.
10957         * @return a new default ParamLabelRenderer
10958         */
10959        public IParamLabelRenderer createDefaultParamLabelRenderer() {
10960            return new DefaultParamLabelRenderer(commandSpec);
10961        }
10962        /** Sorts {@link OptionSpec OptionSpecs} by their option name in case-insensitive alphabetic order. If an
10963         * option has multiple names, the shortest name is used for the sorting. Help options follow non-help options.
10964         * @return a comparator that sorts OptionSpecs by their option name in case-insensitive alphabetic order */
10965        public static Comparator<OptionSpec> createShortOptionNameComparator() {
10966            return new SortByShortestOptionNameAlphabetically();
10967        }
10968        /** Sorts {@link OptionSpec OptionSpecs} by their option {@linkplain Range#max max arity} first, by
10969         * {@linkplain Range#min min arity} next, and by {@linkplain #createShortOptionNameComparator() option name} last.
10970         * @return a comparator that sorts OptionSpecs by arity first, then their option name */
10971        public static Comparator<OptionSpec> createShortOptionArityAndNameComparator() {
10972            return new SortByOptionArityAndNameAlphabetically();
10973        }
10974        /** Sorts short strings before longer strings.
10975         * @return a comparators that sorts short strings before longer strings */
10976        public static Comparator<String> shortestFirst() { return new ShortestFirst(); }
10977        /** Sorts {@link OptionSpec options} by their option {@linkplain IOrdered#order() order}, lowest first, highest last.
10978         * @return a comparator that sorts OptionSpecs by their order
10979         * @since 3.9*/
10980        static Comparator<OptionSpec> createOrderComparator() {
10981            return new SortByOrder<OptionSpec>();
10982        }
10983
10984        /** Returns whether ANSI escape codes are enabled or not.
10985         * @return whether ANSI escape codes are enabled or not
10986         */
10987        public Ansi ansi() { return colorScheme.ansi; }
10988
10989        /** Controls the visibility of certain aspects of the usage help message. */
10990        public enum Visibility { ALWAYS, NEVER, ON_DEMAND }
10991
10992        /** When customizing online help for {@link OptionSpec Option} details, a custom {@code IOptionRenderer} can be
10993         * used to create textual representation of an Option in a tabular format: one or more rows, each containing
10994         * one or more columns. The {@link Layout Layout} is responsible for placing these text values in the
10995         * {@link TextTable TextTable}. */
10996        public interface IOptionRenderer {
10997            /**
10998             * Returns a text representation of the specified option and its parameter(s) if any.
10999             * @param option the command line option to show online usage help for
11000             * @param parameterLabelRenderer responsible for rendering option parameters to text
11001             * @param scheme color scheme for applying ansi color styles to options and option parameters
11002             * @return a 2-dimensional array of text values: one or more rows, each containing one or more columns
11003             * @since 3.0
11004             */
11005            Text[][] render(OptionSpec option, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme);
11006        }
11007        /** The DefaultOptionRenderer converts {@link OptionSpec Options} to five columns of text to match the default
11008         * {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
11009         * <ol>
11010         * <li>the required option marker (if the option is required)</li>
11011         * <li>2-character short option name (or empty string if no short option exists)</li>
11012         * <li>comma separator (only if both short option and long option exist, empty string otherwise)</li>
11013         * <li>comma-separated string with long option name(s)</li>
11014         * <li>first element of the {@link OptionSpec#description()} array</li>
11015         * </ol>
11016         * <p>Following this, there will be one row for each of the remaining elements of the {@link
11017         *   OptionSpec#description()} array, and these rows look like {@code {"", "", "", option.description()[i]}}.</p>
11018         */
11019        static class DefaultOptionRenderer implements IOptionRenderer {
11020            private String requiredMarker = " ";
11021            private boolean showDefaultValues;
11022            private String sep;
11023            public DefaultOptionRenderer(boolean showDefaultValues, String requiredMarker) {
11024                this.showDefaultValues = showDefaultValues;
11025                this.requiredMarker = Assert.notNull(requiredMarker, "requiredMarker");
11026            }
11027            public Text[][] render(OptionSpec option, IParamLabelRenderer paramLabelRenderer, ColorScheme scheme) {
11028                String[] names = ShortestFirst.sort(option.names());
11029                int shortOptionCount = names[0].length() == 2 ? 1 : 0;
11030                String shortOption = shortOptionCount > 0 ? names[0] : "";
11031                sep = shortOptionCount > 0 && names.length > 1 ? "," : "";
11032
11033                String longOption = join(names, shortOptionCount, names.length - shortOptionCount, ", ");
11034                Text longOptionText = createLongOptionText(option, paramLabelRenderer, scheme, longOption);
11035
11036                String requiredOption = option.required() ? requiredMarker : "";
11037                return renderDescriptionLines(option, scheme, requiredOption, shortOption, longOptionText);
11038            }
11039
11040            private Text createLongOptionText(OptionSpec option, IParamLabelRenderer renderer, ColorScheme scheme, String longOption) {
11041                Text paramLabelText = renderer.renderParameterLabel(option, scheme.ansi(), scheme.optionParamStyles);
11042
11043                // if no long option, fill in the space between the short option name and the param label value
11044                if (paramLabelText.length > 0 && longOption.length() == 0) {
11045                    sep = renderer.separator();
11046                    // #181 paramLabelText may be =LABEL or [=LABEL...]
11047                    int sepStart = paramLabelText.plainString().indexOf(sep);
11048                    Text prefix = paramLabelText.substring(0, sepStart);
11049                    paramLabelText = prefix.concat(paramLabelText.substring(sepStart + sep.length()));
11050                }
11051                Text longOptionText = scheme.optionText(longOption);
11052                longOptionText = longOptionText.concat(paramLabelText);
11053                return longOptionText;
11054            }
11055
11056            private Text[][] renderDescriptionLines(OptionSpec option,
11057                                                    ColorScheme scheme,
11058                                                    String requiredOption,
11059                                                    String shortOption,
11060                                                    Text longOptionText) {
11061                Text EMPTY = Ansi.EMPTY_TEXT;
11062                boolean[] showDefault = {option.internalShowDefaultValue(showDefaultValues)};
11063                List<Text[]> result = new ArrayList<Text[]>();
11064                String[] description = option.renderedDescription();
11065                Text[] descriptionFirstLines = createDescriptionFirstLines(scheme, option, description, showDefault);
11066                result.add(new Text[] { scheme.optionText(requiredOption), scheme.optionText(shortOption),
11067                        scheme.ansi().new Text(sep), longOptionText, descriptionFirstLines[0] });
11068                for (int i = 1; i < descriptionFirstLines.length; i++) {
11069                    result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, descriptionFirstLines[i] });
11070                }
11071                for (int i = 1; i < description.length; i++) {
11072                    Text[] descriptionNextLines = scheme.ansi().new Text(description[i]).splitLines();
11073                    for (Text line : descriptionNextLines) {
11074                        result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, line });
11075                    }
11076                }
11077                if (showDefault[0]) { addTrailingDefaultLine(result, option, scheme); }
11078                return result.toArray(new Text[result.size()][]);
11079            }
11080        }
11081        /** The MinimalOptionRenderer converts {@link OptionSpec Options} to a single row with two columns of text: an
11082         * option name and a description. If multiple names or description lines exist, the first value is used. */
11083        static class MinimalOptionRenderer implements IOptionRenderer {
11084            public Text[][] render(OptionSpec option, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme) {
11085                Text optionText = scheme.optionText(option.names()[0]);
11086                Text paramLabelText = parameterLabelRenderer.renderParameterLabel(option, scheme.ansi(), scheme.optionParamStyles);
11087                optionText = optionText.concat(paramLabelText);
11088                return new Text[][] {{ optionText,
11089                                        scheme.ansi().new Text(option.description().length == 0 ? "" : option.description()[0]) }};
11090            }
11091        }
11092        /** The MinimalParameterRenderer converts {@linkplain PositionalParamSpec positional parameters} to a single row with two columns of
11093         * text: the parameters label and a description. If multiple description lines exist, the first value is used. */
11094        static class MinimalParameterRenderer implements IParameterRenderer {
11095            public Text[][] render(PositionalParamSpec param, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme) {
11096                return new Text[][] {{ parameterLabelRenderer.renderParameterLabel(param, scheme.ansi(), scheme.parameterStyles),
11097                        scheme.ansi().new Text(param.description().length == 0 ? "" : param.description()[0]) }};
11098            }
11099        }
11100        /** When customizing online help for {@linkplain PositionalParamSpec positional parameters} details, a custom {@code IParameterRenderer}
11101         * can be used to create textual representation of a Parameters field in a tabular format: one or more rows,
11102         * each containing one or more columns. The {@link Layout Layout} is responsible for placing these text
11103         * values in the {@link TextTable TextTable}. */
11104        public interface IParameterRenderer {
11105            /**
11106             * Returns a text representation of the specified positional parameter.
11107             * @param param the positional parameter to show online usage help for
11108             * @param parameterLabelRenderer responsible for rendering parameter labels to text
11109             * @param scheme color scheme for applying ansi color styles to positional parameters
11110             * @return a 2-dimensional array of text values: one or more rows, each containing one or more columns
11111             * @since 3.0
11112             */
11113            Text[][] render(PositionalParamSpec param, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme);
11114        }
11115        /** The DefaultParameterRenderer converts {@linkplain PositionalParamSpec positional parameters} to five columns of text to match the
11116         * default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
11117         * <ol>
11118         * <li>the required option marker (if the parameter's arity is to have at least one value)</li>
11119         * <li>empty string </li>
11120         * <li>empty string </li>
11121         * <li>parameter(s) label as rendered by the {@link IParamLabelRenderer}</li>
11122         * <li>first element of the {@link PositionalParamSpec#description()} array</li>
11123         * </ol>
11124         * <p>Following this, there will be one row for each of the remaining elements of the {@link
11125         *   PositionalParamSpec#description()} array, and these rows look like {@code {"", "", "", param.description()[i]}}.</p>
11126         */
11127        static class DefaultParameterRenderer implements IParameterRenderer {
11128            private String requiredMarker = " ";
11129            private boolean showDefaultValues;
11130            public DefaultParameterRenderer(boolean showDefaultValues, String requiredMarker) {
11131                this.showDefaultValues = showDefaultValues;
11132                this.requiredMarker = Assert.notNull(requiredMarker, "requiredMarker");
11133            }
11134            public Text[][] render(PositionalParamSpec param, IParamLabelRenderer paramLabelRenderer, ColorScheme scheme) {
11135                Text label = paramLabelRenderer.renderParameterLabel(param, scheme.ansi(), scheme.parameterStyles);
11136                Text requiredParameter = scheme.parameterText(param.arity().min > 0 ? requiredMarker : "");
11137
11138                Text EMPTY = Ansi.EMPTY_TEXT;
11139                boolean[] showDefault = {param.internalShowDefaultValue(showDefaultValues)};
11140                List<Text[]> result = new ArrayList<Text[]>();
11141                String[] description = param.renderedDescription();
11142                Text[] descriptionFirstLines = createDescriptionFirstLines(scheme, param, description, showDefault);
11143                result.add(new Text[] { requiredParameter, EMPTY, EMPTY, label, descriptionFirstLines[0] });
11144                for (int i = 1; i < descriptionFirstLines.length; i++) {
11145                    result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, descriptionFirstLines[i] });
11146                }
11147                for (int i = 1; i < description.length; i++) {
11148                    Text[] descriptionNextLines = scheme.ansi().new Text(description[i]).splitLines();
11149                    for (Text line : descriptionNextLines) {
11150                        result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, line });
11151                    }
11152                }
11153                if (showDefault[0]) { addTrailingDefaultLine(result, param, scheme); }
11154                return result.toArray(new Text[result.size()][]);
11155            }
11156        }
11157
11158        private static void addTrailingDefaultLine(List<Text[]> result, ArgSpec arg, ColorScheme scheme) {
11159            Text EMPTY = Ansi.EMPTY_TEXT;
11160            result.add(new Text[]{EMPTY, EMPTY, EMPTY, EMPTY, scheme.ansi().new Text("  Default: " + arg.defaultValueString())});
11161        }
11162
11163        private static Text[] createDescriptionFirstLines(ColorScheme scheme, ArgSpec arg, String[] description, boolean[] showDefault) {
11164            Text[] result = scheme.ansi().new Text(str(description, 0)).splitLines();
11165            if (result.length == 0 || (result.length == 1 && result[0].plain.length() == 0)) {
11166                if (showDefault[0]) {
11167                    result = new Text[]{scheme.ansi().new Text("  Default: " + arg.defaultValueString())};
11168                    showDefault[0] = false; // don't show the default value twice
11169                } else {
11170                    result = new Text[]{ Ansi.EMPTY_TEXT };
11171                }
11172            }
11173            return result;
11174        }
11175
11176        /** When customizing online usage help for an option parameter or a positional parameter, a custom
11177         * {@code IParamLabelRenderer} can be used to render the parameter name or label to a String. */
11178        public interface IParamLabelRenderer {
11179
11180            /** Returns a text rendering of the option parameter or positional parameter; returns an empty string
11181             * {@code ""} if the option is a boolean and does not take a parameter.
11182             * @param argSpec the named or positional parameter with a parameter label
11183             * @param ansi determines whether ANSI escape codes should be emitted or not
11184             * @param styles the styles to apply to the parameter label
11185             * @return a text rendering of the Option parameter or positional parameter
11186             * @since 3.0 */
11187            Text renderParameterLabel(ArgSpec argSpec, Ansi ansi, List<IStyle> styles);
11188
11189            /** Returns the separator between option name and param label.
11190             * @return the separator between option name and param label */
11191            String separator();
11192        }
11193        /**
11194         * DefaultParamLabelRenderer separates option parameters from their {@linkplain OptionSpec option names} with a
11195         * {@linkplain CommandLine.Model.ParserSpec#separator() separator} string, and, unless
11196         * {@link ArgSpec#hideParamSyntax()} is true, surrounds optional values with {@code '['} and {@code ']'} characters
11197         * and uses ellipses ("...") to indicate that any number of values is allowed for options or parameters with variable arity.
11198         */
11199        static class DefaultParamLabelRenderer implements IParamLabelRenderer {
11200            private final CommandSpec commandSpec;
11201            /** Constructs a new DefaultParamLabelRenderer with the specified separator string. */
11202            public DefaultParamLabelRenderer(CommandSpec commandSpec) {
11203                this.commandSpec = Assert.notNull(commandSpec, "commandSpec");
11204            }
11205            public String separator() { return commandSpec.parser().separator(); }
11206            public Text renderParameterLabel(ArgSpec argSpec, Ansi ansi, List<IStyle> styles) {
11207                Range capacity = argSpec.isOption() ? argSpec.arity() : ((PositionalParamSpec)argSpec).capacity();
11208                if (capacity.max == 0) { return ansi.new Text(""); }
11209                if (argSpec.hideParamSyntax()) { return ansi.apply((argSpec.isOption() ? separator() : "") + argSpec.paramLabel(), styles); }
11210                
11211                Text paramName = ansi.apply(argSpec.paramLabel(), styles);
11212                String split = argSpec.splitRegex();
11213                String mandatorySep = empty(split) ? " "  : split;
11214                String optionalSep  = empty(split) ? " [" : "[" + split;
11215
11216                boolean unlimitedSplit = !empty(split) && !commandSpec.parser().limitSplit();
11217                boolean limitedSplit =   !empty(split) &&  commandSpec.parser().limitSplit();
11218                Text repeating = paramName;
11219                int paramCount = 1;
11220                if (unlimitedSplit) {
11221                    repeating = paramName.concat("[" + split).concat(paramName).concat("...]");
11222                    paramCount++;
11223                    mandatorySep = " ";
11224                    optionalSep = " [";
11225                }
11226                Text result = repeating;
11227
11228                int done = 1;
11229                for (; done < capacity.min; done++) {
11230                    result = result.concat(mandatorySep).concat(repeating); // " PARAM" or ",PARAM"
11231                    paramCount += paramCount;
11232                }
11233                if (!capacity.isVariable) {
11234                    for (int i = done; i < capacity.max; i++) {
11235                        result = result.concat(optionalSep).concat(paramName); // " [PARAM" or "[,PARAM"
11236                        paramCount++;
11237                    }
11238                    for (int i = done; i < capacity.max; i++) {
11239                        result = result.concat("]");
11240                    }
11241                }
11242                // show an extra trailing "[,PARAM]" if split and either max=* or splitting is not restricted to max
11243                boolean effectivelyVariable = capacity.isVariable || (limitedSplit && paramCount == 1);
11244                if (limitedSplit && effectivelyVariable && paramCount == 1) {
11245                    result = result.concat(optionalSep).concat(repeating).concat("]"); // PARAM[,PARAM]...
11246                }
11247                if (effectivelyVariable) {
11248                    if (!argSpec.arity().isVariable && argSpec.arity().min > 1) {
11249                        result = ansi.new Text("(").concat(result).concat(")"); // repeating group
11250                    }
11251                    result = result.concat("..."); // PARAM...
11252                }
11253                String optionSeparator = argSpec.isOption() ? separator() : "";
11254                if (capacity.min == 0) { // optional
11255                    String sep2 = empty(optionSeparator.trim()) ? optionSeparator + "[" : "[" + optionSeparator;
11256                    result = ansi.new Text(sep2).concat(result).concat("]");
11257                } else {
11258                    result = ansi.new Text(optionSeparator).concat(result);
11259                }
11260                return result;
11261            }
11262        }
11263        /** Use a Layout to format usage help text for options and parameters in tabular format.
11264         * <p>Delegates to the renderers to create {@link Text} values for the annotated fields, and uses a
11265         * {@link TextTable} to display these values in tabular format. Layout is responsible for deciding which values
11266         * to display where in the table. By default, Layout shows one option or parameter per table row.</p>
11267         * <p>Customize by overriding the {@link #layout(CommandLine.Model.ArgSpec, CommandLine.Help.Ansi.Text[][])} method.</p>
11268         * @see IOptionRenderer rendering options to text
11269         * @see IParameterRenderer rendering parameters to text
11270         * @see TextTable showing values in a tabular format
11271         */
11272        public static class Layout {
11273            protected final ColorScheme colorScheme;
11274            protected final TextTable table;
11275            protected IOptionRenderer optionRenderer;
11276            protected IParameterRenderer parameterRenderer;
11277
11278            /** Constructs a Layout with the specified color scheme, a new default TextTable, the
11279             * {@linkplain Help#createDefaultOptionRenderer() default option renderer}, and the
11280             * {@linkplain Help#createDefaultParameterRenderer() default parameter renderer}.
11281             * @param colorScheme the color scheme to use for common, auto-generated parts of the usage help message */
11282            public Layout(ColorScheme colorScheme, int tableWidth) { this(colorScheme, TextTable.forDefaultColumns(colorScheme.ansi(), tableWidth)); }
11283
11284            /** Constructs a Layout with the specified color scheme, the specified TextTable, the
11285             * {@linkplain Help#createDefaultOptionRenderer() default option renderer}, and the
11286             * {@linkplain Help#createDefaultParameterRenderer() default parameter renderer}.
11287             * @param colorScheme the color scheme to use for common, auto-generated parts of the usage help message
11288             * @param textTable the TextTable to lay out parts of the usage help message in tabular format */
11289            public Layout(ColorScheme colorScheme, TextTable textTable) {
11290                this(colorScheme, textTable, new DefaultOptionRenderer(false, " "), new DefaultParameterRenderer(false, " "));
11291            }
11292            /** Constructs a Layout with the specified color scheme, the specified TextTable, the
11293             * specified option renderer and the specified parameter renderer.
11294             * @param colorScheme the color scheme to use for common, auto-generated parts of the usage help message
11295             * @param optionRenderer the object responsible for rendering Options to Text
11296             * @param parameterRenderer the object responsible for rendering Parameters to Text
11297             * @param textTable the TextTable to lay out parts of the usage help message in tabular format */
11298            public Layout(ColorScheme colorScheme, TextTable textTable, IOptionRenderer optionRenderer, IParameterRenderer parameterRenderer) {
11299                this.colorScheme       = Assert.notNull(colorScheme, "colorScheme");
11300                this.table             = Assert.notNull(textTable, "textTable");
11301                this.optionRenderer    = Assert.notNull(optionRenderer, "optionRenderer");
11302                this.parameterRenderer = Assert.notNull(parameterRenderer, "parameterRenderer");
11303            }
11304            /**
11305             * Copies the specified text values into the correct cells in the {@link TextTable}. This implementation
11306             * delegates to {@link TextTable#addRowValues(CommandLine.Help.Ansi.Text...)} for each row of values.
11307             * <p>Subclasses may override.</p>
11308             * @param argSpec the Option or Parameters
11309             * @param cellValues the text values representing the Option/Parameters, to be displayed in tabular form
11310             * @since 3.0 */
11311            public void layout(ArgSpec argSpec, Text[][] cellValues) {
11312                for (Text[] oneRow : cellValues) {
11313                    table.addRowValues(oneRow);
11314                }
11315            }
11316            /** Calls {@link #addOption(CommandLine.Model.OptionSpec, CommandLine.Help.IParamLabelRenderer)} for all non-hidden Options in the list.
11317             * @param options options to add usage descriptions for
11318             * @param paramLabelRenderer object that knows how to render option parameters
11319             * @since 3.0 */
11320            public void addOptions(List<OptionSpec> options, IParamLabelRenderer paramLabelRenderer) {
11321                for (OptionSpec option : options) {
11322                    if (!option.hidden()) {
11323                        addOption(option, paramLabelRenderer);
11324                    }
11325                }
11326            }
11327            /**
11328             * Delegates to the {@link #optionRenderer option renderer} of this layout to obtain
11329             * text values for the specified {@link OptionSpec}, and then calls the {@link #layout(CommandLine.Model.ArgSpec, CommandLine.Help.Ansi.Text[][])}
11330             * method to write these text values into the correct cells in the TextTable.
11331             * @param option the option argument
11332             * @param paramLabelRenderer knows how to render option parameters
11333             * @since 3.0 */
11334            public void addOption(OptionSpec option, IParamLabelRenderer paramLabelRenderer) {
11335                Text[][] values = optionRenderer.render(option, paramLabelRenderer, colorScheme);
11336                layout(option, values);
11337            }
11338            /** Calls {@link #addPositionalParameter(CommandLine.Model.PositionalParamSpec, CommandLine.Help.IParamLabelRenderer)} for all non-hidden Parameters in the list.
11339             * @param params positional parameters to add usage descriptions for
11340             * @param paramLabelRenderer knows how to render option parameters
11341             * @since 3.0 */
11342            public void addPositionalParameters(List<PositionalParamSpec> params, IParamLabelRenderer paramLabelRenderer) {
11343                for (PositionalParamSpec param : params) {
11344                    if (!param.hidden()) {
11345                        addPositionalParameter(param, paramLabelRenderer);
11346                    }
11347                }
11348            }
11349            /**
11350             * Delegates to the {@link #parameterRenderer parameter renderer} of this layout
11351             * to obtain text values for the specified {@linkplain PositionalParamSpec positional parameter}, and then calls
11352             * {@link #layout(CommandLine.Model.ArgSpec, CommandLine.Help.Ansi.Text[][])} to write these text values into the correct cells in the TextTable.
11353             * @param param the positional parameter
11354             * @param paramLabelRenderer knows how to render option parameters
11355             * @since 3.0 */
11356            public void addPositionalParameter(PositionalParamSpec param, IParamLabelRenderer paramLabelRenderer) {
11357                Text[][] values = parameterRenderer.render(param, paramLabelRenderer, colorScheme);
11358                layout(param, values);
11359            }
11360            /** Returns the section of the usage help message accumulated in the TextTable owned by this layout. */
11361            @Override public String toString() { return table.toString(); }
11362        }
11363        /** Sorts short strings before longer strings. */
11364        static class ShortestFirst implements Comparator<String> {
11365            public int compare(String o1, String o2) {
11366                return o1.length() - o2.length();
11367            }
11368            /** Sorts the specified array of Strings shortest-first and returns it. */
11369            public static String[] sort(String[] names) {
11370                Arrays.sort(names, new ShortestFirst());
11371                return names;
11372            }
11373            /** Sorts the specified array of Strings longest-first and returns it. */
11374            public static String[] longestFirst(String[] names) {
11375                Arrays.sort(names, Collections.reverseOrder(new ShortestFirst()));
11376                return names;
11377            }
11378        }
11379        /** Sorts {@code OptionSpec} instances by their name in case-insensitive alphabetic order. If an option has
11380         * multiple names, the shortest name is used for the sorting. Help options follow non-help options. */
11381        static class SortByShortestOptionNameAlphabetically implements Comparator<OptionSpec> {
11382            public int compare(OptionSpec o1, OptionSpec o2) {
11383                if (o1 == null) { return 1; } else if (o2 == null) { return -1; } // options before params
11384                String[] names1 = ShortestFirst.sort(o1.names());
11385                String[] names2 = ShortestFirst.sort(o2.names());
11386                int result = names1[0].toUpperCase().compareTo(names2[0].toUpperCase()); // case insensitive sort
11387                result = result == 0 ? -names1[0].compareTo(names2[0]) : result; // lower case before upper case
11388                return o1.help() == o2.help() ? result : o2.help() ? -1 : 1; // help options come last
11389            }
11390        }
11391        /** Sorts {@code OptionSpec} instances by their max arity first, then their min arity, then delegates to super class. */
11392        static class SortByOptionArityAndNameAlphabetically extends SortByShortestOptionNameAlphabetically {
11393            public int compare(OptionSpec o1, OptionSpec o2) {
11394                Range arity1 = o1.arity();
11395                Range arity2 = o2.arity();
11396                int result = arity1.max - arity2.max;
11397                if (result == 0) {
11398                    result = arity1.min - arity2.min;
11399                }
11400                if (result == 0) { // arity is same
11401                    if (o1.isMultiValue() && !o2.isMultiValue()) { result = 1; } // f1 > f2
11402                    if (!o1.isMultiValue() && o2.isMultiValue()) { result = -1; } // f1 < f2
11403                }
11404                return result == 0 ? super.compare(o1, o2) : result;
11405            }
11406        }
11407        static class SortByOrder<T extends IOrdered> implements Comparator<T> {
11408            public int compare(T o1, T o2) {
11409                return Integer.signum(o1.order() - o2.order());
11410            }
11411        }
11412        /**
11413         * <p>Responsible for spacing out {@link Text} values according to the {@link Column} definitions the table was
11414         * created with. Columns have a width, indentation, and an overflow policy that decides what to do if a value is
11415         * longer than the column's width.</p>
11416         */
11417        public static class TextTable {
11418            /**
11419             * Helper class to index positions in a {@code Help.TextTable}.
11420             * @since 2.0
11421             */
11422            public static class Cell {
11423                /** Table column index (zero based). */
11424                public final int column;
11425                /** Table row index (zero based). */
11426                public final int row;
11427                /** Constructs a new Cell with the specified coordinates in the table.
11428                 * @param column the zero-based table column
11429                 * @param row the zero-based table row */
11430                public Cell(int column, int row) { this.column = column; this.row = row; }
11431            }
11432
11433            private static final int OPTION_SEPARATOR_COLUMN = 2;
11434            private static final int LONG_OPTION_COLUMN = 3;
11435
11436            /** The column definitions of this table. */
11437            private final Column[] columns;
11438
11439            /** The {@code char[]} slots of the {@code TextTable} to copy text values into. */
11440            protected final List<Text> columnValues = new ArrayList<Text>();
11441
11442            /** By default, indent wrapped lines by 2 spaces. */
11443            public int indentWrappedLines = 2;
11444
11445            private final Ansi ansi;
11446            private final int tableWidth;
11447
11448            /** Constructs a TextTable with five columns as follows:
11449             * <ol>
11450             * <li>required option/parameter marker (width: 2, indent: 0, TRUNCATE on overflow)</li>
11451             * <li>short option name (width: 2, indent: 0, TRUNCATE on overflow)</li>
11452             * <li>comma separator (width: 1, indent: 0, TRUNCATE on overflow)</li>
11453             * <li>long option name(s) (width: 24, indent: 1, SPAN multiple columns on overflow)</li>
11454             * <li>description line(s) (width: 51, indent: 1, WRAP to next row on overflow)</li>
11455             * </ol>
11456             * @param ansi whether to emit ANSI escape codes or not
11457             * @param usageHelpWidth the total width of the columns combined
11458             */
11459            public static TextTable forDefaultColumns(Ansi ansi, int usageHelpWidth) {
11460                return forDefaultColumns(ansi, defaultOptionsColumnWidth, usageHelpWidth);
11461            }
11462
11463            /** Constructs a TextTable with five columns as follows:
11464             * <ol>
11465             * <li>required option/parameter marker (width: 2, indent: 0, TRUNCATE on overflow)</li>
11466             * <li>short option name (width: 2, indent: 0, TRUNCATE on overflow)</li>
11467             * <li>comma separator (width: 1, indent: 0, TRUNCATE on overflow)</li>
11468             * <li>long option name(s) (width: 24, indent: 1, SPAN multiple columns on overflow)</li>
11469             * <li>description line(s) (width: 51, indent: 1, WRAP to next row on overflow)</li>
11470             * </ol>
11471             * @param ansi whether to emit ANSI escape codes or not
11472             * @param longOptionsColumnWidth the width of the long options column
11473             * @param usageHelpWidth the total width of the columns combined
11474             */
11475            public static TextTable forDefaultColumns(Ansi ansi, int longOptionsColumnWidth, int usageHelpWidth) {
11476                // "* -c, --create                Creates a ...."
11477                return forColumns(ansi,
11478                        new Column(2,                                       0, TRUNCATE), // "*"
11479                        new Column(2,                                       0, TRUNCATE), // "-c"
11480                        new Column(1,                                       0, TRUNCATE), // ","
11481                        new Column(longOptionsColumnWidth,                         1, SPAN),  // " --create"
11482                        new Column(usageHelpWidth - longOptionsColumnWidth, 1, WRAP)); // " Creates a ..."
11483            }
11484
11485            /** Constructs a new TextTable with columns with the specified width, all SPANning  multiple columns on
11486             * overflow except the last column which WRAPS to the next row.
11487             * @param ansi whether to emit ANSI escape codes or not
11488             * @param columnWidths the width of each table column (all columns have zero indent)
11489             */
11490            public static TextTable forColumnWidths(Ansi ansi, int... columnWidths) {
11491                Column[] columns = new Column[columnWidths.length];
11492                for (int i = 0; i < columnWidths.length; i++) {
11493                    columns[i] = new Column(columnWidths[i], 0, i == columnWidths.length - 1 ? WRAP : SPAN);
11494                }
11495                return new TextTable(ansi, columns);
11496            }
11497            /** Constructs a {@code TextTable} with the specified columns.
11498             * @param ansi whether to emit ANSI escape codes or not
11499             * @param columns columns to construct this TextTable with */
11500            public static TextTable forColumns(Ansi ansi, Column... columns) { return new TextTable(ansi, columns); }
11501            protected TextTable(Ansi ansi, Column[] columns) {
11502                this.ansi = Assert.notNull(ansi, "ansi");
11503                this.columns = Assert.notNull(columns, "columns").clone();
11504                if (columns.length == 0) { throw new IllegalArgumentException("At least one column is required"); }
11505                int totalWidth = 0;
11506                for (Column col : columns) { totalWidth += col.width; }
11507                tableWidth = totalWidth;
11508            }
11509            /** The column definitions of this table. */
11510            public Column[] columns() { return columns.clone(); }
11511            /** Returns the {@code Text} slot at the specified row and column to write a text value into.
11512             * @param row the row of the cell whose Text to return
11513             * @param col the column of the cell whose Text to return
11514             * @return the Text object at the specified row and column
11515             * @since 2.0 */
11516            public Text textAt(int row, int col) { return columnValues.get(col + (row * columns.length)); }
11517
11518            /** Returns the {@code Text} slot at the specified row and column to write a text value into.
11519             * @param row the row of the cell whose Text to return
11520             * @param col the column of the cell whose Text to return
11521             * @return the Text object at the specified row and column
11522             * @deprecated use {@link #textAt(int, int)} instead */
11523            @Deprecated public Text cellAt(int row, int col) { return textAt(row, col); }
11524
11525            /** Returns the current number of rows of this {@code TextTable}.
11526             * @return the current number of rows in this TextTable */
11527            public int rowCount() { return columnValues.size() / columns.length; }
11528
11529            /** Adds the required {@code char[]} slots for a new row to the {@link #columnValues} field. */
11530            public void addEmptyRow() {
11531                for (int i = 0; i < columns.length; i++) {
11532                    columnValues.add(ansi.new Text(columns[i].width));
11533                }
11534            }
11535
11536            /** Delegates to {@link #addRowValues(CommandLine.Help.Ansi.Text...)}.
11537             * @param values the text values to display in each column of the current row */
11538            public void addRowValues(String... values) {
11539                Text[] array = new Text[values.length];
11540                for (int i = 0; i < array.length; i++) {
11541                    array[i] = values[i] == null ? Ansi.EMPTY_TEXT : ansi.new Text(values[i]);
11542                }
11543                addRowValues(array);
11544            }
11545            /**
11546             * Adds a new {@linkplain TextTable#addEmptyRow() empty row}, then calls {@link
11547             * TextTable#putValue(int, int, CommandLine.Help.Ansi.Text) putValue} for each of the specified values, adding more empty rows
11548             * if the return value indicates that the value spanned multiple columns or was wrapped to multiple rows.
11549             * @param values the values to write into a new row in this TextTable
11550             * @throws IllegalArgumentException if the number of values exceeds the number of Columns in this table
11551             */
11552            public void addRowValues(Text... values) {
11553                if (values.length > columns.length) {
11554                    throw new IllegalArgumentException(values.length + " values don't fit in " +
11555                            columns.length + " columns");
11556                }
11557                addEmptyRow();
11558                int oldIndent = unindent(values);
11559                for (int col = 0; col < values.length; col++) {
11560                    int row = rowCount() - 1;// write to last row: previous value may have wrapped to next row
11561                    Cell cell = putValue(row, col, values[col]);
11562
11563                    // add row if a value spanned/wrapped and there are still remaining values
11564                    if ((cell.row != row || cell.column != col) && col != values.length - 1) {
11565                        addEmptyRow();
11566                    }
11567                }
11568                reindent(oldIndent);
11569            }
11570            private int unindent(Text[] values) {
11571                if (columns.length <= LONG_OPTION_COLUMN) { return 0; }
11572                int oldIndent = columns[LONG_OPTION_COLUMN].indent;
11573                if ("=".equals(values[OPTION_SEPARATOR_COLUMN].toString())) {
11574                    columns[LONG_OPTION_COLUMN].indent = 0;
11575                }
11576                return oldIndent;
11577            }
11578            private void reindent(int oldIndent) {
11579                if (columns.length <= LONG_OPTION_COLUMN) { return; }
11580                columns[LONG_OPTION_COLUMN].indent = oldIndent;
11581            }
11582
11583            /**
11584             * Writes the specified value into the cell at the specified row and column and returns the last row and
11585             * column written to. Depending on the Column's {@link Column#overflow Overflow} policy, the value may span
11586             * multiple columns or wrap to multiple rows when larger than the column width.
11587             * @param row the target row in the table
11588             * @param col the target column in the table to write to
11589             * @param value the value to write
11590             * @return a Cell indicating the position in the table that was last written to (since 2.0)
11591             * @throws IllegalArgumentException if the specified row exceeds the table's {@linkplain
11592             *          TextTable#rowCount() row count}
11593             * @since 2.0 (previous versions returned a {@code java.awt.Point} object)
11594             */
11595            public Cell putValue(int row, int col, Text value) {
11596                if (row > rowCount() - 1) {
11597                    throw new IllegalArgumentException("Cannot write to row " + row + ": rowCount=" + rowCount());
11598                }
11599                if (value == null || value.plain.length() == 0) { return new Cell(col, row); }
11600                Column column = columns[col];
11601                int indent = column.indent;
11602                switch (column.overflow) {
11603                    case TRUNCATE:
11604                        copy(value, textAt(row, col), indent);
11605                        return new Cell(col, row);
11606                    case SPAN:
11607                        int startColumn = col;
11608                        do {
11609                            boolean lastColumn = col == columns.length - 1;
11610                            int charsWritten = lastColumn
11611                                    ? copy(BreakIterator.getLineInstance(), value, textAt(row, col), indent)
11612                                    : copy(value, textAt(row, col), indent);
11613                            value = value.substring(charsWritten);
11614                            indent = 0;
11615                            if (value.length > 0) { // value did not fit in column
11616                                ++col;                // write remainder of value in next column
11617                            }
11618                            if (value.length > 0 && col >= columns.length) { // we filled up all columns on this row
11619                                addEmptyRow();
11620                                row++;
11621                                col = startColumn;
11622                                indent = column.indent + indentWrappedLines;
11623                            }
11624                        } while (value.length > 0);
11625                        return new Cell(col, row);
11626                    case WRAP:
11627                        BreakIterator lineBreakIterator = BreakIterator.getLineInstance();
11628                        do {
11629                            int charsWritten = copy(lineBreakIterator, value, textAt(row, col), indent);
11630                            value = value.substring(charsWritten);
11631                            indent = column.indent + indentWrappedLines;
11632                            if (value.length > 0) {  // value did not fit in column
11633                                ++row;                 // write remainder of value in next row
11634                                addEmptyRow();
11635                            }
11636                        } while (value.length > 0);
11637                        return new Cell(col, row);
11638                }
11639                throw new IllegalStateException(column.overflow.toString());
11640            }
11641            private static int length(Text str) {
11642                return str.length; // TODO count some characters as double length
11643            }
11644
11645            private int copy(BreakIterator line, Text text, Text columnValue, int offset) {
11646                // Deceive the BreakIterator to ensure no line breaks after '-' character
11647                line.setText(text.plainString().replace("-", "\u00ff"));
11648                int done = 0;
11649                for (int start = line.first(), end = line.next(); end != BreakIterator.DONE; start = end, end = line.next()) {
11650                    Text word = text.substring(start, end); //.replace("\u00ff", "-"); // not needed
11651                    if (columnValue.maxLength >= offset + done + length(word)) {
11652                        done += copy(word, columnValue, offset + done); // TODO messages length
11653                    } else {
11654                        break;
11655                    }
11656                }
11657                if (done == 0 && length(text) + offset > columnValue.maxLength) {
11658                    // The value is a single word that is too big to be written to the column. Write as much as we can.
11659                    done = copy(text, columnValue, offset);
11660                }
11661                return done;
11662            }
11663            private static int copy(Text value, Text destination, int offset) {
11664                int length = Math.min(value.length, destination.maxLength - offset);
11665                value.getStyledChars(value.from, length, destination, offset);
11666                return length;
11667            }
11668
11669            /** Copies the text representation that we built up from the options into the specified StringBuilder.
11670             * @param text the StringBuilder to write into
11671             * @return the specified StringBuilder object (to allow method chaining and a more fluid API) */
11672            public StringBuilder toString(StringBuilder text) {
11673                int columnCount = this.columns.length;
11674                StringBuilder row = new StringBuilder(tableWidth);
11675                for (int i = 0; i < columnValues.size(); i++) {
11676                    Text column = columnValues.get(i);
11677                    row.append(column.toString());
11678                    row.append(new String(spaces(columns[i % columnCount].width - column.length)));
11679                    if (i % columnCount == columnCount - 1) {
11680                        int lastChar = row.length() - 1;
11681                        while (lastChar >= 0 && row.charAt(lastChar) == ' ') {lastChar--;} // rtrim
11682                        row.setLength(lastChar + 1);
11683                        text.append(row.toString()).append(System.getProperty("line.separator"));
11684                        row.setLength(0);
11685                    }
11686                }
11687                return text;
11688            }
11689            public String toString() { return toString(new StringBuilder()).toString(); }
11690        }
11691        /** Columns define the width, indent (leading number of spaces in a column before the value) and
11692         * {@linkplain Overflow Overflow} policy of a column in a {@linkplain TextTable TextTable}. */
11693        public static class Column {
11694
11695            /** Policy for handling text that is longer than the column width:
11696             *  span multiple columns, wrap to the next row, or simply truncate the portion that doesn't fit. */
11697            public enum Overflow { TRUNCATE, SPAN, WRAP }
11698
11699            /** Column width in characters */
11700            public final int width;
11701
11702            /** Indent (number of empty spaces at the start of the column preceding the text value) */
11703            public int indent;
11704
11705            /** Policy that determines how to handle values larger than the column width. */
11706            public final Overflow overflow;
11707            public Column(int width, int indent, Overflow overflow) {
11708                this.width = width;
11709                this.indent = indent;
11710                this.overflow = Assert.notNull(overflow, "overflow");
11711            }
11712        }
11713
11714        /** All usage help message are generated with a color scheme that assigns certain styles and colors to common
11715         * parts of a usage message: the command name, options, positional parameters and option parameters.
11716         * Users may customize these styles by creating Help with a custom color scheme.
11717         * <p>Note that these options and styles may not be rendered if ANSI escape codes are not
11718         * {@linkplain Ansi#enabled() enabled}.</p>
11719         * @see Help#defaultColorScheme(Ansi)
11720         */
11721        public static class ColorScheme {
11722            public final List<IStyle> commandStyles = new ArrayList<IStyle>();
11723            public final List<IStyle> optionStyles = new ArrayList<IStyle>();
11724            public final List<IStyle> parameterStyles = new ArrayList<IStyle>();
11725            public final List<IStyle> optionParamStyles = new ArrayList<IStyle>();
11726            private final Ansi ansi;
11727
11728            /** Constructs a new empty ColorScheme with {@link Help.Ansi#AUTO}. */
11729            public ColorScheme() { this(Ansi.AUTO); }
11730
11731            /** Constructs a new empty ColorScheme with the specified Ansi enabled mode.
11732             * @see Help#defaultColorScheme(Ansi)
11733             * @param ansi whether to emit ANSI escape codes or not
11734             */
11735            public ColorScheme(Ansi ansi) {this.ansi = Assert.notNull(ansi, "ansi"); }
11736
11737            /** Adds the specified styles to the registered styles for commands in this color scheme and returns this color scheme.
11738             * @param styles the styles to add to the registered styles for commands in this color scheme
11739             * @return this color scheme to enable method chaining for a more fluent API */
11740            public ColorScheme commands(IStyle... styles)     { return addAll(commandStyles, styles); }
11741            /** Adds the specified styles to the registered styles for options in this color scheme and returns this color scheme.
11742             * @param styles the styles to add to registered the styles for options in this color scheme
11743             * @return this color scheme to enable method chaining for a more fluent API */
11744            public ColorScheme options(IStyle... styles)      { return addAll(optionStyles, styles);}
11745            /** Adds the specified styles to the registered styles for positional parameters in this color scheme and returns this color scheme.
11746             * @param styles the styles to add to registered the styles for parameters in this color scheme
11747             * @return this color scheme to enable method chaining for a more fluent API */
11748            public ColorScheme parameters(IStyle... styles)   { return addAll(parameterStyles, styles);}
11749            /** Adds the specified styles to the registered styles for option parameters in this color scheme and returns this color scheme.
11750             * @param styles the styles to add to the registered styles for option parameters in this color scheme
11751             * @return this color scheme to enable method chaining for a more fluent API */
11752            public ColorScheme optionParams(IStyle... styles) { return addAll(optionParamStyles, styles);}
11753            /** Returns a Text with all command styles applied to the specified command string.
11754             * @param command the command string to apply the registered command styles to
11755             * @return a Text with all command styles applied to the specified command string */
11756            public Ansi.Text commandText(String command)         { return ansi().apply(command,     commandStyles); }
11757            /** Returns a Text with all option styles applied to the specified option string.
11758             * @param option the option string to apply the registered option styles to
11759             * @return a Text with all option styles applied to the specified option string */
11760            public Ansi.Text optionText(String option)           { return ansi().apply(option,      optionStyles); }
11761            /** Returns a Text with all parameter styles applied to the specified parameter string.
11762             * @param parameter the parameter string to apply the registered parameter styles to
11763             * @return a Text with all parameter styles applied to the specified parameter string */
11764            public Ansi.Text parameterText(String parameter)     { return ansi().apply(parameter,   parameterStyles); }
11765            /** Returns a Text with all optionParam styles applied to the specified optionParam string.
11766             * @param optionParam the option parameter string to apply the registered option parameter styles to
11767             * @return a Text with all option parameter styles applied to the specified option parameter string */
11768            public Ansi.Text optionParamText(String optionParam) { return ansi().apply(optionParam, optionParamStyles); }
11769
11770            /** Replaces colors and styles in this scheme with ones specified in system properties, and returns this scheme.
11771             * Supported property names:<ul>
11772             *     <li>{@code picocli.color.commands}</li>
11773             *     <li>{@code picocli.color.options}</li>
11774             *     <li>{@code picocli.color.parameters}</li>
11775             *     <li>{@code picocli.color.optionParams}</li>
11776             * </ul><p>Property values can be anything that {@link Help.Ansi.Style#parse(String)} can handle.</p>
11777             * @return this ColorScheme
11778             */
11779            public ColorScheme applySystemProperties() {
11780                replace(commandStyles,     System.getProperty("picocli.color.commands"));
11781                replace(optionStyles,      System.getProperty("picocli.color.options"));
11782                replace(parameterStyles,   System.getProperty("picocli.color.parameters"));
11783                replace(optionParamStyles, System.getProperty("picocli.color.optionParams"));
11784                return this;
11785            }
11786            private void replace(List<IStyle> styles, String property) {
11787                if (property != null) {
11788                    styles.clear();
11789                    addAll(styles, Style.parse(property));
11790                }
11791            }
11792            private ColorScheme addAll(List<IStyle> styles, IStyle... add) {
11793                styles.addAll(Arrays.asList(add));
11794                return this;
11795            }
11796
11797            public Ansi ansi() { return ansi; }
11798        }
11799
11800        /** Creates and returns a new {@link ColorScheme} initialized with picocli default values: commands are bold,
11801         *  options and parameters use a yellow foreground, and option parameters use italic.
11802         * @param ansi whether the usage help message should contain ANSI escape codes or not
11803         * @return a new default color scheme
11804         */
11805        public static ColorScheme defaultColorScheme(Ansi ansi) {
11806            return new ColorScheme(ansi)
11807                    .commands(Style.bold)
11808                    .options(Style.fg_yellow)
11809                    .parameters(Style.fg_yellow)
11810                    .optionParams(Style.italic);
11811        }
11812
11813        /** Provides methods and inner classes to support using ANSI escape codes in usage help messages. */
11814        public enum Ansi {
11815            /** Only emit ANSI escape codes if the platform supports it and system property {@code "picocli.ansi"}
11816             * is not set to any value other than {@code "true"} (case insensitive). */
11817            AUTO,
11818            /** Forced ON: always emit ANSI escape code regardless of the platform. */
11819            ON,
11820            /** Forced OFF: never emit ANSI escape code regardless of the platform. */
11821            OFF;
11822            static Text EMPTY_TEXT = OFF.new Text(0);
11823
11824            static Boolean tty;
11825            static boolean isTTY() {
11826                if (tty == null) { tty = calcTTY(); }
11827                return tty;
11828            }
11829            static final boolean isWindows()    { return System.getProperty("os.name").startsWith("Windows"); }
11830            static final boolean isXterm()      { return System.getenv("TERM") != null && System.getenv("TERM").startsWith("xterm"); }
11831            // null on Windows unless on Cygwin or MSYS
11832            static final boolean hasOsType()    { return System.getenv("OSTYPE") != null; }
11833
11834            // see Jan Niklas Hasse's https://bixense.com/clicolors/ proposal
11835            // https://conemu.github.io/en/AnsiEscapeCodes.html#Environment_variable
11836            static final boolean hintDisabled() { return "0".equals(System.getenv("CLICOLOR"))
11837                                               || "OFF".equals(System.getenv("ConEmuANSI")); }
11838
11839            /** https://github.com/adoxa/ansicon/blob/master/readme.txt,
11840             * Jan Niklas Hasse's https://bixense.com/clicolors/ proposal,
11841             * https://conemu.github.io/en/AnsiEscapeCodes.html#Environment_variable */
11842            static final boolean hintEnabled() { return System.getenv("ANSICON") != null
11843                                               || "1".equals(System.getenv("CLICOLOR"))
11844                                               || "ON".equals(System.getenv("ConEmuANSI")); }
11845            /** https://no-color.org/ */
11846            static final boolean forceDisabled() { return System.getenv("NO_COLOR") != null; }
11847
11848            /** Jan Niklas Hasse's https://bixense.com/clicolors/ proposal */
11849            static final boolean forceEnabled() { return System.getenv("CLICOLOR_FORCE") != null
11850                                               && !"0".equals(System.getenv("CLICOLOR_FORCE"));}
11851            /** http://stackoverflow.com/questions/1403772/how-can-i-check-if-a-java-programs-input-output-streams-are-connected-to-a-term */
11852            static boolean calcTTY() {
11853                try { return System.class.getDeclaredMethod("console").invoke(null) != null; }
11854                catch (Throwable reflectionFailed) { return true; }
11855            }
11856            /** Cygwin and MSYS use pseudo-tty and console is always null... */
11857            static boolean isPseudoTTY() { return isWindows() && (isXterm() || hasOsType()); }
11858
11859            static boolean ansiPossible() {
11860                if (forceDisabled())                          { return false; }
11861                if (forceEnabled())                           { return true; }
11862                if (isWindows() && isJansiConsoleInstalled()) { return true; } // #630 JVM crash loading jansi.AnsiConsole on Linux
11863                if (hintDisabled())                           { return false; }
11864                if (!isTTY() && !isPseudoTTY())               { return false; }
11865                return hintEnabled() || !isWindows() || isXterm() || hasOsType();
11866            }
11867            static boolean isJansiConsoleInstalled() {
11868                try {
11869                    Class<?> ansiConsole = Class.forName("org.fusesource.jansi.AnsiConsole");
11870                    Field out = ansiConsole.getField("out");
11871                    return out.get(null) == System.out;
11872                } catch (Exception reflectionFailed) {
11873                    return false;
11874                }
11875            }
11876            
11877            /** Returns {@code true} if ANSI escape codes should be emitted, {@code false} otherwise.
11878             * @return ON: {@code true}, OFF: {@code false}, AUTO: if system property {@code "picocli.ansi"} is
11879             *      defined then return its boolean value, otherwise return whether the platform supports ANSI escape codes */
11880            public boolean enabled() {
11881                if (this == ON)  { return true; }
11882                if (this == OFF) { return false; }
11883                String ansi = System.getProperty("picocli.ansi");
11884                boolean auto = ansi == null || "AUTO".equalsIgnoreCase(ansi);
11885                return auto ? ansiPossible() : Boolean.getBoolean("picocli.ansi");
11886            }
11887            /**
11888             * Returns a new Text object for this Ansi mode, encapsulating the specified string
11889             * which may contain markup like {@code @|bg(red),white,underline some text|@}.
11890             * <p>
11891             * Calling {@code toString()} on the returned Text will either include ANSI escape codes
11892             * (if this Ansi mode is ON), or suppress ANSI escape codes (if this Ansi mode is OFF).
11893             * <p>
11894             * Equivalent to {@code this.new Text(stringWithMarkup)}.
11895             * @since 3.4 */
11896            public Text text(String stringWithMarkup) { return this.new Text(stringWithMarkup); }
11897
11898            /**
11899             * Returns a String where any markup like
11900             * {@code @|bg(red),white,underline some text|@} is converted to ANSI escape codes
11901             * if this Ansi is ON, or suppressed if this Ansi is OFF.
11902             * <p>
11903             * Equivalent to {@code this.new Text(stringWithMarkup).toString()}.
11904             * @since 3.4 */
11905            public String string(String stringWithMarkup) { return this.new Text(stringWithMarkup).toString(); }
11906
11907            /** Returns Ansi.ON if the specified {@code enabled} flag is true, Ansi.OFF otherwise.
11908             * @since 3.4 */
11909            public static Ansi valueOf(boolean enabled) {return enabled ? ON : OFF; }
11910
11911            /** Defines the interface for an ANSI escape sequence. */
11912            public interface IStyle {
11913
11914                /** The Control Sequence Introducer (CSI) escape sequence {@value}. */
11915                String CSI = "\u001B[";
11916
11917                /** Returns the ANSI escape code for turning this style on.
11918                 * @return the ANSI escape code for turning this style on */
11919                String on();
11920
11921                /** Returns the ANSI escape code for turning this style off.
11922                 * @return the ANSI escape code for turning this style off */
11923                String off();
11924            }
11925
11926            /**
11927             * A set of pre-defined ANSI escape code styles and colors, and a set of convenience methods for parsing
11928             * text with embedded markup style names, as well as convenience methods for converting
11929             * styles to strings with embedded escape codes.
11930             */
11931            public enum Style implements IStyle {
11932                reset(0, 0), bold(1, 21), faint(2, 22), italic(3, 23), underline(4, 24), blink(5, 25), reverse(7, 27),
11933                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),
11934                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),
11935                ;
11936                private final int startCode;
11937                private final int endCode;
11938
11939                Style(int startCode, int endCode) {this.startCode = startCode; this.endCode = endCode; }
11940                public String on() { return CSI + startCode + "m"; }
11941                public String off() { return CSI + endCode + "m"; }
11942
11943                /** Returns the concatenated ANSI escape codes for turning all specified styles on.
11944                 * @param styles the styles to generate ANSI escape codes for
11945                 * @return the concatenated ANSI escape codes for turning all specified styles on */
11946                public static String on(IStyle... styles) {
11947                    StringBuilder result = new StringBuilder();
11948                    for (IStyle style : styles) {
11949                        result.append(style.on());
11950                    }
11951                    return result.toString();
11952                }
11953                /** Returns the concatenated ANSI escape codes for turning all specified styles off.
11954                 * @param styles the styles to generate ANSI escape codes for
11955                 * @return the concatenated ANSI escape codes for turning all specified styles off */
11956                public static String off(IStyle... styles) {
11957                    StringBuilder result = new StringBuilder();
11958                    for (IStyle style : styles) {
11959                        result.append(style.off());
11960                    }
11961                    return result.toString();
11962                }
11963                /** Parses the specified style markup and returns the associated style.
11964                 *  The markup may be one of the Style enum value names, or it may be one of the Style enum value
11965                 *  names when {@code "fg_"} is prepended, or it may be one of the indexed colors in the 256 color palette.
11966                 * @param str the case-insensitive style markup to convert, e.g. {@code "blue"} or {@code "fg_blue"},
11967                 *          or {@code "46"} (indexed color) or {@code "0;5;0"} (RGB components of an indexed color)
11968                 * @return the IStyle for the specified converter
11969                 */
11970                public static IStyle fg(String str) {
11971                    try { return Style.valueOf(str.toLowerCase(ENGLISH)); } catch (Exception ignored) {}
11972                    try { return Style.valueOf("fg_" + str.toLowerCase(ENGLISH)); } catch (Exception ignored) {}
11973                    return new Palette256Color(true, str);
11974                }
11975                /** Parses the specified style markup and returns the associated style.
11976                 *  The markup may be one of the Style enum value names, or it may be one of the Style enum value
11977                 *  names when {@code "bg_"} is prepended, or it may be one of the indexed colors in the 256 color palette.
11978                 * @param str the case-insensitive style markup to convert, e.g. {@code "blue"} or {@code "bg_blue"},
11979                 *          or {@code "46"} (indexed color) or {@code "0;5;0"} (RGB components of an indexed color)
11980                 * @return the IStyle for the specified converter
11981                 */
11982                public static IStyle bg(String str) {
11983                    try { return Style.valueOf(str.toLowerCase(ENGLISH)); } catch (Exception ignored) {}
11984                    try { return Style.valueOf("bg_" + str.toLowerCase(ENGLISH)); } catch (Exception ignored) {}
11985                    return new Palette256Color(false, str);
11986                }
11987                /** Parses the specified comma-separated sequence of style descriptors and returns the associated
11988                 *  styles. For each markup, strings starting with {@code "bg("} are delegated to
11989                 *  {@link #bg(String)}, others are delegated to {@link #bg(String)}.
11990                 * @param commaSeparatedCodes one or more descriptors, e.g. {@code "bg(blue),underline,red"}
11991                 * @return an array with all styles for the specified descriptors
11992                 */
11993                public static IStyle[] parse(String commaSeparatedCodes) {
11994                    String[] codes = commaSeparatedCodes.split(",");
11995                    IStyle[] styles = new IStyle[codes.length];
11996                    for(int i = 0; i < codes.length; ++i) {
11997                        if (codes[i].toLowerCase(ENGLISH).startsWith("fg(")) {
11998                            int end = codes[i].indexOf(')');
11999                            styles[i] = Style.fg(codes[i].substring(3, end < 0 ? codes[i].length() : end));
12000                        } else if (codes[i].toLowerCase(ENGLISH).startsWith("bg(")) {
12001                            int end = codes[i].indexOf(')');
12002                            styles[i] = Style.bg(codes[i].substring(3, end < 0 ? codes[i].length() : end));
12003                        } else {
12004                            styles[i] = Style.fg(codes[i]);
12005                        }
12006                    }
12007                    return styles;
12008                }
12009            }
12010
12011            /** Defines a palette map of 216 colors: 6 * 6 * 6 cube (216 colors):
12012             * 16 + 36 * r + 6 * g + b (0 &lt;= r, g, b &lt;= 5). */
12013            static class Palette256Color implements IStyle {
12014                private final int fgbg;
12015                private final int color;
12016
12017                Palette256Color(boolean foreground, String color) {
12018                    this.fgbg = foreground ? 38 : 48;
12019                    String[] rgb = color.split(";");
12020                    if (rgb.length == 3) {
12021                        this.color = 16 + 36 * Integer.decode(rgb[0]) + 6 * Integer.decode(rgb[1]) + Integer.decode(rgb[2]);
12022                    } else {
12023                        this.color = Integer.decode(color);
12024                    }
12025                }
12026                public String on() { return String.format(CSI + "%d;5;%dm", fgbg, color); }
12027                public String off() { return CSI + (fgbg + 1) + "m"; }
12028            }
12029            private static class StyledSection {
12030                int startIndex, length;
12031                String startStyles, endStyles;
12032                StyledSection(int start, int len, String style1, String style2) {
12033                    startIndex = start; length = len; startStyles = style1; endStyles = style2;
12034                }
12035                StyledSection withStartIndex(int newStart) {
12036                    return new StyledSection(newStart, length, startStyles, endStyles);
12037                }
12038            }
12039
12040            /**
12041             * Returns a new Text object where all the specified styles are applied to the full length of the
12042             * specified plain text.
12043             * @param plainText the string to apply all styles to. Must not contain markup!
12044             * @param styles the styles to apply to the full plain text
12045             * @return a new Text object
12046             */
12047            public Text apply(String plainText, List<IStyle> styles) {
12048                if (plainText.length() == 0) { return new Text(0); }
12049                Text result = new Text(plainText.length());
12050                IStyle[] all = styles.toArray(new IStyle[styles.size()]);
12051                result.sections.add(new StyledSection(
12052                        0, plainText.length(), Style.on(all), Style.off(reverse(all)) + Style.reset.off()));
12053                result.plain.append(plainText);
12054                result.length = result.plain.length();
12055                return result;
12056            }
12057
12058            private static <T> T[] reverse(T[] all) {
12059                for (int i = 0; i < all.length / 2; i++) {
12060                    T temp = all[i];
12061                    all[i] = all[all.length - i - 1];
12062                    all[all.length - i - 1] = temp;
12063                }
12064                return all;
12065            }
12066            /** Encapsulates rich text with styles and colors. Text objects may be constructed with Strings containing
12067             * markup like {@code @|bg(red),white,underline some text|@}, and this class converts the markup to ANSI
12068             * escape codes.
12069             * <p>
12070             * Internally keeps both an enriched and a plain text representation to allow layout components to calculate
12071             * text width while remaining unaware of the embedded ANSI escape codes.</p> */
12072            public class Text implements Cloneable {
12073                private final int maxLength;
12074                private int from;
12075                private int length;
12076                private StringBuilder plain = new StringBuilder();
12077                private List<StyledSection> sections = new ArrayList<StyledSection>();
12078
12079                /** Constructs a Text with the specified max length (for use in a TextTable Column).
12080                 * @param maxLength max length of this text */
12081                public Text(int maxLength) { this.maxLength = maxLength; }
12082
12083                /** Copy constructor.
12084                 * @since 3.9 */
12085                public Text(Text other) {
12086                    this.maxLength = other.maxLength;
12087                    this.from = other.from;
12088                    this.length = other.length;
12089                    this.plain = new StringBuilder(other.plain);
12090                    this.sections = new ArrayList<StyledSection>(other.sections);
12091                }
12092                /**
12093                 * Constructs a Text with the specified String, which may contain markup like
12094                 * {@code @|bg(red),white,underline some text|@}.
12095                 * @param input the string with markup to parse
12096                 */
12097                public Text(String input) {
12098                    maxLength = -1;
12099                    plain.setLength(0);
12100                    int i = 0;
12101
12102                    while (true) {
12103                        int j = input.indexOf("@|", i);
12104                        if (j == -1) {
12105                            if (i == 0) {
12106                                plain.append(input);
12107                                length = plain.length();
12108                                return;
12109                            }
12110                            plain.append(input.substring(i, input.length()));
12111                            length = plain.length();
12112                            return;
12113                        }
12114                        plain.append(input.substring(i, j));
12115                        int k = input.indexOf("|@", j);
12116                        if (k == -1) {
12117                            plain.append(input);
12118                            length = plain.length();
12119                            return;
12120                        }
12121
12122                        j += 2;
12123                        String spec = input.substring(j, k);
12124                        String[] items = spec.split(" ", 2);
12125                        if (items.length == 1) {
12126                            plain.append(input);
12127                            length = plain.length();
12128                            return;
12129                        }
12130
12131                        IStyle[] styles = Style.parse(items[0]);
12132                        addStyledSection(plain.length(), items[1].length(),
12133                                Style.on(styles), Style.off(reverse(styles)) + Style.reset.off());
12134                        plain.append(items[1]);
12135                        i = k + 2;
12136                    }
12137                }
12138                private void addStyledSection(int start, int length, String startStyle, String endStyle) {
12139                    sections.add(new StyledSection(start, length, startStyle, endStyle));
12140                }
12141                public Object clone() { return new Text(this); }
12142
12143                public Text[] splitLines() {
12144                    List<Text> result = new ArrayList<Text>();
12145                    int start = 0, end = 0;
12146                    for (int i = 0; i < plain.length(); i++, end = i) {
12147                        char c = plain.charAt(i);
12148                        boolean eol = c == '\n';
12149                        if (c == '\r' && i + 1 < plain.length() && plain.charAt(i + 1) == '\n') { eol = true; i++; } // \r\n
12150                        eol |= c == '\r';
12151                        if (eol) {
12152                            result.add(this.substring(start, end));
12153                            start = i + 1;
12154                        }
12155                    }
12156                    // add remainder (may be empty string)
12157                    result.add(this.substring(start, plain.length()));
12158                    return result.toArray(new Text[result.size()]);
12159                }
12160
12161                /** Returns a new {@code Text} instance that is a substring of this Text. Does not modify this instance!
12162                 * @param start index in the plain text where to start the substring
12163                 * @return a new Text instance that is a substring of this Text */
12164                public Text substring(int start) {
12165                    return substring(start, length);
12166                }
12167
12168                /** Returns a new {@code Text} instance that is a substring of this Text. Does not modify this instance!
12169                 * @param start index in the plain text where to start the substring
12170                 * @param end index in the plain text where to end the substring
12171                 * @return a new Text instance that is a substring of this Text */
12172                public Text substring(int start, int end) {
12173                    Text result = (Text) clone();
12174                    result.from = from + start;
12175                    result.length = end - start;
12176                    return result;
12177                }
12178                /** @deprecated use {@link #concat(String)} instead */
12179                @Deprecated public Text append(String string) { return concat(string); }
12180                /** @deprecated use {@link #concat(Text)} instead */
12181                @Deprecated public Text append(Text text) { return concat(text); }
12182
12183                /** Returns a copy of this {@code Text} instance with the specified text concatenated to the end. Does not modify this instance!
12184                 * @param string the text to concatenate to the end of this Text
12185                 * @return a new Text instance
12186                 * @since 3.0 */
12187                public Text concat(String string) { return concat(new Text(string)); }
12188
12189                /** Returns a copy of this {@code Text} instance with the specified text concatenated to the end. Does not modify this instance!
12190                 * @param other the text to concatenate to the end of this Text
12191                 * @return a new Text instance
12192                 * @since 3.0 */
12193                public Text concat(Text other) {
12194                    Text result = (Text) clone();
12195                    result.plain = new StringBuilder(plain.toString().substring(from, from + length));
12196                    result.from = 0;
12197                    result.sections = new ArrayList<StyledSection>();
12198                    for (StyledSection section : sections) {
12199                        result.sections.add(section.withStartIndex(section.startIndex - from));
12200                    }
12201                    result.plain.append(other.plain.toString().substring(other.from, other.from + other.length));
12202                    for (StyledSection section : other.sections) {
12203                        int index = result.length + section.startIndex - other.from;
12204                        result.sections.add(section.withStartIndex(index));
12205                    }
12206                    result.length = result.plain.length();
12207                    return result;
12208                }
12209
12210                /**
12211                 * Copies the specified substring of this Text into the specified destination, preserving the markup.
12212                 * @param from start of the substring
12213                 * @param length length of the substring
12214                 * @param destination destination Text to modify
12215                 * @param offset indentation (padding)
12216                 */
12217                public void getStyledChars(int from, int length, Text destination, int offset) {
12218                    if (destination.length < offset) {
12219                        for (int i = destination.length; i < offset; i++) {
12220                            destination.plain.append(' ');
12221                        }
12222                        destination.length = offset;
12223                    }
12224                    for (StyledSection section : sections) {
12225                        destination.sections.add(section.withStartIndex(section.startIndex - from + destination.length));
12226                    }
12227                    destination.plain.append(plain.toString().substring(from, from + length));
12228                    destination.length = destination.plain.length();
12229                }
12230                /** Returns the plain text without any formatting.
12231                 * @return the plain text without any formatting */
12232                public String plainString() {  return plain.toString().substring(from, from + length); }
12233
12234                public boolean equals(Object obj) { return toString().equals(String.valueOf(obj)); }
12235                public int hashCode() { return toString().hashCode(); }
12236
12237                /** Returns a String representation of the text with ANSI escape codes embedded, unless ANSI is
12238                 * {@linkplain Ansi#enabled()} not enabled}, in which case the plain text is returned.
12239                 * @return a String representation of the text with ANSI escape codes embedded (if enabled) */
12240                public String toString() {
12241                    if (!Ansi.this.enabled()) {
12242                        return plain.toString().substring(from, from + length);
12243                    }
12244                    if (length == 0) { return ""; }
12245                    StringBuilder sb = new StringBuilder(plain.length() + 20 * sections.size());
12246                    StyledSection current = null;
12247                    int end = Math.min(from + length, plain.length());
12248                    for (int i = from; i < end; i++) {
12249                        StyledSection section = findSectionContaining(i);
12250                        if (section != current) {
12251                            if (current != null) { sb.append(current.endStyles); }
12252                            if (section != null) { sb.append(section.startStyles); }
12253                            current = section;
12254                        }
12255                        sb.append(plain.charAt(i));
12256                    }
12257                    if (current != null) { sb.append(current.endStyles); }
12258                    return sb.toString();
12259                }
12260
12261                private StyledSection findSectionContaining(int index) {
12262                    for (StyledSection section : sections) {
12263                        if (index >= section.startIndex && index < section.startIndex + section.length) {
12264                            return section;
12265                        }
12266                    }
12267                    return null;
12268                }
12269            }
12270        }
12271    }
12272
12273    /**
12274     * Utility class providing some defensive coding convenience methods.
12275     */
12276    private static final class Assert {
12277        /**
12278         * Throws a NullPointerException if the specified object is null.
12279         * @param object the object to verify
12280         * @param description error message
12281         * @param <T> type of the object to check
12282         * @return the verified object
12283         */
12284        static <T> T notNull(T object, String description) {
12285            if (object == null) {
12286                throw new NullPointerException(description);
12287            }
12288            return object;
12289        }
12290        static boolean equals(Object obj1, Object obj2) { return obj1 == null ? obj2 == null : obj1.equals(obj2); }
12291        static int hashCode(Object obj) {return obj == null ? 0 : obj.hashCode(); }
12292        static int hashCode(boolean bool) {return bool ? 1 : 0; }
12293        static void assertTrue(boolean condition, String message) {
12294            if (!condition) throw new IllegalStateException(message);
12295        }
12296        private Assert() {} // private constructor: never instantiate
12297    }
12298    private enum TraceLevel { OFF, WARN, INFO, DEBUG;
12299        public boolean isEnabled(TraceLevel other) { return ordinal() >= other.ordinal(); }
12300        private void print(Tracer tracer, String msg, Object... params) {
12301            if (tracer.level.isEnabled(this)) { tracer.stream.printf(prefix(msg), params); }
12302        }
12303        private String prefix(String msg) { return "[picocli " + this + "] " + msg; }
12304        static TraceLevel lookup(String key) { return key == null ? WARN : empty(key) || "true".equalsIgnoreCase(key) ? INFO : valueOf(key); }
12305    }
12306    static class Tracer {
12307        TraceLevel level = TraceLevel.lookup(System.getProperty("picocli.trace"));
12308        PrintStream stream = System.err;
12309        void warn (String msg, Object... params) { TraceLevel.WARN.print(this, msg, params); }
12310        void info (String msg, Object... params) { TraceLevel.INFO.print(this, msg, params); }
12311        void debug(String msg, Object... params) { TraceLevel.DEBUG.print(this, msg, params); }
12312        boolean isWarn()  { return level.isEnabled(TraceLevel.WARN); }
12313        boolean isInfo()  { return level.isEnabled(TraceLevel.INFO); }
12314        boolean isDebug() { return level.isEnabled(TraceLevel.DEBUG); }
12315    }
12316    /**
12317     * Uses cosine similarity to find matches from a candidate set for a specified input.
12318     * Based on code from http://www.nearinfinity.com/blogs/seth_schroeder/groovy_cosine_similarity_in_grails.html
12319     *
12320     * @author Burt Beckwith
12321     */
12322    private static class CosineSimilarity {
12323        static List<String> mostSimilar(String pattern, Iterable<String> candidates) { return mostSimilar(pattern, candidates, 0); }
12324        static List<String> mostSimilar(String pattern, Iterable<String> candidates, double threshold) {
12325            pattern = pattern.toLowerCase();
12326            SortedMap<Double, String> sorted = new TreeMap<Double, String>();
12327            for (String candidate : candidates) {
12328                double score = similarity(pattern, candidate.toLowerCase(), 2);
12329                if (score > threshold) { sorted.put(score, candidate); }
12330            }
12331            return reverseList(new ArrayList<String>(sorted.values()));
12332        }
12333
12334        private static double similarity(String sequence1, String sequence2, int degree) {
12335            Map<String, Integer> m1 = countNgramFrequency(sequence1, degree);
12336            Map<String, Integer> m2 = countNgramFrequency(sequence2, degree);
12337            return dotProduct(m1, m2) / Math.sqrt(dotProduct(m1, m1) * dotProduct(m2, m2));
12338        }
12339
12340        private static Map<String, Integer> countNgramFrequency(String sequence, int degree) {
12341            Map<String, Integer> m = new HashMap<String, Integer>();
12342            for (int i = 0; i + degree <= sequence.length(); i++) {
12343                String gram = sequence.substring(i, i + degree);
12344                m.put(gram, 1 + (m.containsKey(gram) ? m.get(gram) : 0));
12345            }
12346            return m;
12347        }
12348
12349        private static double dotProduct(Map<String, Integer> m1, Map<String, Integer> m2) {
12350            double result = 0;
12351            for (String key : m1.keySet()) { result += m1.get(key) * (m2.containsKey(key) ? m2.get(key) : 0); }
12352            return result;
12353        }
12354    }
12355    /** Base class of all exceptions thrown by {@code picocli.CommandLine}.
12356     * <h2>Class Diagram of the Picocli Exceptions</h2>
12357     * <p>
12358     * <img src="doc-files/class-diagram-exceptions.png" alt="Class Diagram of the Picocli Exceptions">
12359     * </p>
12360     * @since 2.0 */
12361    public static class PicocliException extends RuntimeException {
12362        private static final long serialVersionUID = -2574128880125050818L;
12363        public PicocliException(String msg) { super(msg); }
12364        public PicocliException(String msg, Throwable t) { super(msg, t); }
12365    }
12366    /** Exception indicating a problem during {@code CommandLine} initialization.
12367     * @since 2.0 */
12368    public static class InitializationException extends PicocliException {
12369        private static final long serialVersionUID = 8423014001666638895L;
12370        public InitializationException(String msg) { super(msg); }
12371        public InitializationException(String msg, Exception ex) { super(msg, ex); }
12372    }
12373    /** Exception indicating a problem while invoking a command or subcommand.
12374     * @since 2.0 */
12375    public static class ExecutionException extends PicocliException {
12376        private static final long serialVersionUID = 7764539594267007998L;
12377        private final CommandLine commandLine;
12378        public ExecutionException(CommandLine commandLine, String msg) {
12379            super(msg);
12380            this.commandLine = Assert.notNull(commandLine, "commandLine");
12381        }
12382        public ExecutionException(CommandLine commandLine, String msg, Throwable t) {
12383            super(msg, t);
12384            this.commandLine = Assert.notNull(commandLine, "commandLine");
12385        }
12386        /** Returns the {@code CommandLine} object for the (sub)command that could not be invoked.
12387         * @return the {@code CommandLine} object for the (sub)command where invocation failed.
12388         */
12389        public CommandLine getCommandLine() { return commandLine; }
12390    }
12391
12392    /** Exception thrown by {@link ITypeConverter} implementations to indicate a String could not be converted. */
12393    public static class TypeConversionException extends PicocliException {
12394        private static final long serialVersionUID = 4251973913816346114L;
12395        public TypeConversionException(String msg) { super(msg); }
12396    }
12397    /** Exception indicating something went wrong while parsing command line options. */
12398    public static class ParameterException extends PicocliException {
12399        private static final long serialVersionUID = 1477112829129763139L;
12400        private final CommandLine commandLine;
12401        private ArgSpec argSpec = null;
12402        private String value = null;
12403
12404        /** Constructs a new ParameterException with the specified CommandLine and error message.
12405         * @param commandLine the command or subcommand whose input was invalid
12406         * @param msg describes the problem
12407         * @since 2.0 */
12408        public ParameterException(CommandLine commandLine, String msg) {
12409            super(msg);
12410            this.commandLine = Assert.notNull(commandLine, "commandLine");
12411        }
12412
12413        /** Constructs a new ParameterException with the specified CommandLine and error message.
12414         * @param commandLine the command or subcommand whose input was invalid
12415         * @param msg describes the problem
12416         * @param t the throwable that caused this ParameterException
12417         * @since 2.0 */
12418        public ParameterException(CommandLine commandLine, String msg, Throwable t) {
12419            super(msg, t);
12420            this.commandLine = Assert.notNull(commandLine, "commandLine");
12421        }
12422
12423        /** Constructs a new ParameterException with the specified CommandLine and error message.
12424         * @param commandLine the command or subcommand whose input was invalid
12425         * @param msg describes the problem
12426         * @param t the throwable that caused this ParameterException
12427         * @param argSpec the argSpec that caused this ParameterException
12428         * @param value the value that caused this ParameterException
12429         * @since 3.2 */
12430        public ParameterException(CommandLine commandLine, String msg, Throwable t, ArgSpec argSpec, String value) {
12431            super(msg, t);
12432            this.commandLine = Assert.notNull(commandLine, "commandLine");
12433            if (argSpec == null && value == null) { throw new IllegalArgumentException("ArgSpec and value cannot both be null"); }
12434            this.argSpec = argSpec;
12435            this.value = value;
12436        }
12437
12438        /** Constructs a new ParameterException with the specified CommandLine and error message.
12439         * @param commandLine the command or subcommand whose input was invalid
12440         * @param msg describes the problem
12441         * @param argSpec the argSpec that caused this ParameterException
12442         * @param value the value that caused this ParameterException
12443         * @since 3.2 */
12444        public ParameterException(CommandLine commandLine, String msg, ArgSpec argSpec, String value) {
12445            super(msg);
12446            this.commandLine = Assert.notNull(commandLine, "commandLine");
12447            if (argSpec == null && value == null) { throw new IllegalArgumentException("ArgSpec and value cannot both be null"); }
12448            this.argSpec = argSpec;
12449            this.value = value;
12450        }
12451
12452
12453        /** Returns the {@code CommandLine} object for the (sub)command whose input could not be parsed.
12454         * @return the {@code CommandLine} object for the (sub)command where parsing failed.
12455         * @since 2.0
12456         */
12457        public CommandLine getCommandLine() { return commandLine; }
12458
12459        /** Returns the {@code ArgSpec} object for the (sub)command whose input could not be parsed.
12460         * @return the {@code ArgSpec} object for the (sub)command where parsing failed.
12461         * @since 3.2
12462         */
12463        public ArgSpec getArgSpec() { return argSpec; }
12464
12465        /** Returns the {@code String} value for the (sub)command whose input could not be parsed.
12466         * @return the {@code String} value for the (sub)command where parsing failed.
12467         * @since 3.2
12468         */
12469        public String getValue() { return value; }
12470
12471        private static ParameterException create(CommandLine cmd, Exception ex, String arg, int i, String[] args) {
12472            String msg = ex.getClass().getSimpleName() + ": " + ex.getLocalizedMessage()
12473                    + " while processing argument at or before arg[" + i + "] '" + arg + "' in " + Arrays.toString(args) + ": " + ex.toString();
12474            return new ParameterException(cmd, msg, ex, null, arg);
12475        }
12476    }
12477    /**
12478     * Exception indicating that a required parameter was not specified.
12479     */
12480    public static class MissingParameterException extends ParameterException {
12481        private static final long serialVersionUID = 5075678535706338753L;
12482        private final List<ArgSpec> missing;
12483        public MissingParameterException(CommandLine commandLine, ArgSpec missing, String msg) { this(commandLine, Arrays.asList(missing), msg); }
12484        public MissingParameterException(CommandLine commandLine, Collection<ArgSpec> missing, String msg) {
12485            super(commandLine, msg);
12486            this.missing = Collections.unmodifiableList(new ArrayList<ArgSpec>(missing));
12487        }
12488        public List<ArgSpec> getMissing() { return missing; }
12489        private static MissingParameterException create(CommandLine cmd, Collection<ArgSpec> missing, String separator) {
12490            if (missing.size() == 1) {
12491                return new MissingParameterException(cmd, missing, "Missing required option '"
12492                        + ArgSpec.describe(missing.iterator().next(), separator) + "'");
12493            }
12494            List<String> names = new ArrayList<String>(missing.size());
12495            for (ArgSpec argSpec : missing) {
12496                names.add(ArgSpec.describe(argSpec, separator));
12497            }
12498            return new MissingParameterException(cmd, missing, "Missing required options " + names.toString());
12499        }
12500    }
12501    /** Exception indicating that the user input included multiple arguments from a mutually exclusive group.
12502     * @since 4.0 */
12503    public static class MutuallyExclusiveArgsException extends ParameterException {
12504        private static final long serialVersionUID = -5557715106221420986L;
12505        public MutuallyExclusiveArgsException(CommandLine commandLine, String msg) { super(commandLine, msg); }
12506    }
12507
12508    /** Exception indicating that multiple named elements have incorrectly used the same name.
12509     * @since 4.0 */
12510    public static class DuplicateNameException extends InitializationException {
12511        private static final long serialVersionUID = -4126747467955626054L;
12512        public DuplicateNameException(String msg) { super(msg); }
12513    }
12514    /**
12515     * Exception indicating that multiple fields have been annotated with the same Option name.
12516     */
12517    public static class DuplicateOptionAnnotationsException extends DuplicateNameException {
12518        private static final long serialVersionUID = -3355128012575075641L;
12519        public DuplicateOptionAnnotationsException(String msg) { super(msg); }
12520
12521        private static DuplicateOptionAnnotationsException create(String name, ArgSpec argSpec1, ArgSpec argSpec2) {
12522            return new DuplicateOptionAnnotationsException("Option name '" + name + "' is used by both " +
12523                    argSpec1.toString() + " and " + argSpec2.toString());
12524        }
12525    }
12526    /** Exception indicating that there was a gap in the indices of the fields annotated with {@link Parameters}. */
12527    public static class ParameterIndexGapException extends InitializationException {
12528        private static final long serialVersionUID = -1520981133257618319L;
12529        public ParameterIndexGapException(String msg) { super(msg); }
12530    }
12531    /** Exception indicating that a command line argument could not be mapped to any of the fields annotated with
12532     * {@link Option} or {@link Parameters}. */
12533    public static class UnmatchedArgumentException extends ParameterException {
12534        private static final long serialVersionUID = -8700426380701452440L;
12535        private List<String> unmatched = Collections.<String>emptyList();
12536        public UnmatchedArgumentException(CommandLine commandLine, String msg) { super(commandLine, msg); }
12537        public UnmatchedArgumentException(CommandLine commandLine, Stack<String> args) { this(commandLine, new ArrayList<String>(reverse(args))); }
12538        public UnmatchedArgumentException(CommandLine commandLine, List<String> args) {
12539            this(commandLine, describe(args, commandLine) + (args.size() == 1 ? ": " : "s: ") + str(args));
12540            unmatched = args == null ? Collections.<String>emptyList() : args;
12541        }
12542        /** Returns {@code true} and prints suggested solutions to the specified stream if such solutions exist, otherwise returns {@code false}.
12543         * @since 3.3.0 */
12544        public static boolean printSuggestions(ParameterException ex, PrintStream out) {
12545            return ex instanceof UnmatchedArgumentException && ((UnmatchedArgumentException) ex).printSuggestions(out);
12546        }
12547        /** Returns the unmatched command line arguments.
12548         * @since 3.3.0 */
12549        public List<String> getUnmatched() { return stripErrorMessage(unmatched); }
12550        static List<String> stripErrorMessage(List<String> unmatched) {
12551            List<String> result = new ArrayList<String>();
12552            for (String s : unmatched) {
12553                if (s == null) { result.add(null); }
12554                int pos = s.indexOf(" (while processing option:");
12555                result.add(pos < 0 ? s : s.substring(0, pos));
12556            }
12557            return Collections.unmodifiableList(result);
12558        }
12559        /** Returns {@code true} if the first unmatched command line arguments resembles an option, {@code false} otherwise.
12560         * @since 3.3.0 */
12561        public boolean isUnknownOption() { return isUnknownOption(unmatched, getCommandLine()); }
12562        /** Returns {@code true} and prints suggested solutions to the specified stream if such solutions exist, otherwise returns {@code false}.
12563         * @since 3.3.0 */
12564        public boolean printSuggestions(PrintStream out) {
12565            List<String> suggestions = getSuggestions();
12566            if (!suggestions.isEmpty()) {
12567                out.println(isUnknownOption()
12568                        ? "Possible solutions: " + str(suggestions)
12569                        : "Did you mean: " + str(suggestions).replace(", ", " or ") + "?");
12570            }
12571            return !suggestions.isEmpty();
12572        }
12573        /** Returns suggested solutions if such solutions exist, otherwise returns an empty list.
12574         * @since 3.3.0 */
12575        public List<String> getSuggestions() {
12576            if (unmatched == null || unmatched.isEmpty()) { return Collections.emptyList(); }
12577            String arg = unmatched.get(0);
12578            String stripped = CommandSpec.stripPrefix(arg);
12579            CommandSpec spec = getCommandLine().getCommandSpec();
12580            if (spec.resemblesOption(arg, null)) {
12581                return spec.findOptionNamesWithPrefix(stripped.substring(0, Math.min(2, stripped.length())));
12582            } else if (!spec.subcommands().isEmpty()) {
12583                List<String> mostSimilar = CosineSimilarity.mostSimilar(arg, spec.subcommands().keySet());
12584                return mostSimilar.subList(0, Math.min(3, mostSimilar.size()));
12585            }
12586            return Collections.emptyList();
12587        }
12588        private static boolean isUnknownOption(List<String> unmatch, CommandLine cmd) {
12589            return unmatch != null && !unmatch.isEmpty() && cmd.getCommandSpec().resemblesOption(unmatch.get(0), null);
12590        }
12591        private static String describe(List<String> unmatch, CommandLine cmd) {
12592            return isUnknownOption(unmatch, cmd) ? "Unknown option" : "Unmatched argument";
12593        }
12594        static String str(List<String> list) {
12595            String s = list.toString();
12596            return s.substring(0, s.length() - 1).substring(1);
12597        }
12598    }
12599    /** Exception indicating that more values were specified for an option or parameter than its {@link Option#arity() arity} allows. */
12600    public static class MaxValuesExceededException extends ParameterException {
12601        private static final long serialVersionUID = 6536145439570100641L;
12602        public MaxValuesExceededException(CommandLine commandLine, String msg) { super(commandLine, msg); }
12603    }
12604    /** Exception indicating that an option for a single-value option field has been specified multiple times on the command line. */
12605    public static class OverwrittenOptionException extends ParameterException {
12606        private static final long serialVersionUID = 1338029208271055776L;
12607        private final ArgSpec overwrittenArg;
12608        public OverwrittenOptionException(CommandLine commandLine, ArgSpec overwritten, String msg) {
12609            super(commandLine, msg);
12610            overwrittenArg = overwritten;
12611        }
12612        /** Returns the {@link ArgSpec} for the option which was being overwritten.
12613         * @since 3.8 */
12614        public ArgSpec getOverwritten() { return overwrittenArg; }
12615    }
12616    /**
12617     * Exception indicating that an annotated field had a type for which no {@link ITypeConverter} was
12618     * {@linkplain #registerConverter(Class, ITypeConverter) registered}.
12619     */
12620    public static class MissingTypeConverterException extends ParameterException {
12621        private static final long serialVersionUID = -6050931703233083760L;
12622        public MissingTypeConverterException(CommandLine commandLine, String msg) { super(commandLine, msg); }
12623    }
12624}