001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.logging.log4j.core.tools.picocli;
018
019import java.io.File;
020import java.io.PrintStream;
021import java.lang.annotation.ElementType;
022import java.lang.annotation.Retention;
023import java.lang.annotation.RetentionPolicy;
024import java.lang.annotation.Target;
025import java.lang.reflect.Array;
026import java.lang.reflect.Constructor;
027import java.lang.reflect.Field;
028import java.lang.reflect.ParameterizedType;
029import java.lang.reflect.Type;
030import java.lang.reflect.WildcardType;
031import java.math.BigDecimal;
032import java.math.BigInteger;
033import java.net.InetAddress;
034import java.net.MalformedURLException;
035import java.net.URI;
036import java.net.URISyntaxException;
037import java.net.URL;
038import java.nio.charset.Charset;
039import java.nio.file.Path;
040import java.nio.file.Paths;
041import java.sql.Time;
042import java.text.BreakIterator;
043import java.text.ParseException;
044import java.text.SimpleDateFormat;
045import java.util.ArrayList;
046import java.util.Arrays;
047import java.util.Collection;
048import java.util.Collections;
049import java.util.Comparator;
050import java.util.Date;
051import java.util.HashMap;
052import java.util.HashSet;
053import java.util.LinkedHashMap;
054import java.util.LinkedHashSet;
055import java.util.LinkedList;
056import java.util.List;
057import java.util.Map;
058import java.util.Queue;
059import java.util.Set;
060import java.util.SortedSet;
061import java.util.Stack;
062import java.util.TreeSet;
063import java.util.UUID;
064import java.util.concurrent.Callable;
065import java.util.regex.Pattern;
066
067import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.IStyle;
068import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.Style;
069import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.Text;
070
071import static java.util.Locale.ENGLISH;
072import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.SPAN;
073import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.TRUNCATE;
074import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.WRAP;
075
076/**
077 * <p>
078 * CommandLine interpreter that uses reflection to initialize an annotated domain object with values obtained from the
079 * command line arguments.
080 * </p><h2>Example</h2>
081 * <pre>import static picocli.CommandLine.*;
082 *
083 * &#064;Command(header = "Encrypt FILE(s), or standard input, to standard output or to the output file.",
084 *          version = "v1.2.3")
085 * public class Encrypt {
086 *
087 *     &#064;Parameters(type = File.class, description = "Any number of input files")
088 *     private List&lt;File&gt; files = new ArrayList&lt;File&gt;();
089 *
090 *     &#064;Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
091 *     private File outputFile;
092 *
093 *     &#064;Option(names = { "-v", "--verbose"}, description = "Verbosely list files processed")
094 *     private boolean verbose;
095 *
096 *     &#064;Option(names = { "-h", "--help", "-?", "-help"}, usageHelp = true, description = "Display this help and exit")
097 *     private boolean help;
098 *
099 *     &#064;Option(names = { "-V", "--version"}, versionHelp = true, description = "Display version info and exit")
100 *     private boolean versionHelp;
101 * }
102 * </pre>
103 * <p>
104 * Use {@code CommandLine} to initialize a domain object as follows:
105 * </p><pre>
106 * public static void main(String... args) {
107 *     Encrypt encrypt = new Encrypt();
108 *     try {
109 *         List&lt;CommandLine&gt; parsedCommands = new CommandLine(encrypt).parse(args);
110 *         if (!CommandLine.printHelpIfRequested(parsedCommands, System.err, Help.Ansi.AUTO)) {
111 *             runProgram(encrypt);
112 *         }
113 *     } catch (ParameterException ex) { // command line arguments could not be parsed
114 *         System.err.println(ex.getMessage());
115 *         ex.getCommandLine().usage(System.err);
116 *     }
117 * }
118 * </pre><p>
119 * Invoke the above program with some command line arguments. The below are all equivalent:
120 * </p>
121 * <pre>
122 * --verbose --out=outfile in1 in2
123 * --verbose --out outfile in1 in2
124 * -v --out=outfile in1 in2
125 * -v -o outfile in1 in2
126 * -v -o=outfile in1 in2
127 * -vo outfile in1 in2
128 * -vo=outfile in1 in2
129 * -v -ooutfile in1 in2
130 * -vooutfile in1 in2
131 * </pre>
132 */
133public class CommandLine {
134    /** This is picocli version {@value}. */
135    public static final String VERSION = "2.0.3";
136
137    private final Tracer tracer = new Tracer();
138    private final Interpreter interpreter;
139    private String commandName = Help.DEFAULT_COMMAND_NAME;
140    private boolean overwrittenOptionsAllowed = false;
141    private boolean unmatchedArgumentsAllowed = false;
142    private final List<String> unmatchedArguments = new ArrayList<>();
143    private CommandLine parent;
144    private boolean usageHelpRequested;
145    private boolean versionHelpRequested;
146    private final List<String> versionLines = new ArrayList<>();
147
148    /**
149     * Constructs a new {@code CommandLine} interpreter with the specified annotated object.
150     * When the {@link #parse(String...)} method is called, fields of the specified object that are annotated
151     * with {@code @Option} or {@code @Parameters} will be initialized based on command line arguments.
152     * @param command the object to initialize from the command line arguments
153     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
154     */
155    public CommandLine(final Object command) {
156        interpreter = new Interpreter(command);
157    }
158
159    /** Registers a subcommand with the specified name. For example:
160     * <pre>
161     * CommandLine commandLine = new CommandLine(new Git())
162     *         .addSubcommand("status",   new GitStatus())
163     *         .addSubcommand("commit",   new GitCommit();
164     *         .addSubcommand("add",      new GitAdd())
165     *         .addSubcommand("branch",   new GitBranch())
166     *         .addSubcommand("checkout", new GitCheckout())
167     *         //...
168     *         ;
169     * </pre>
170     *
171     * <p>The specified object can be an annotated object or a
172     * {@code CommandLine} instance with its own nested subcommands. For example:</p>
173     * <pre>
174     * CommandLine commandLine = new CommandLine(new MainCommand())
175     *         .addSubcommand("cmd1",                 new ChildCommand1()) // subcommand
176     *         .addSubcommand("cmd2",                 new ChildCommand2())
177     *         .addSubcommand("cmd3", new CommandLine(new ChildCommand3()) // subcommand with nested sub-subcommands
178     *                 .addSubcommand("cmd3sub1",                 new GrandChild3Command1())
179     *                 .addSubcommand("cmd3sub2",                 new GrandChild3Command2())
180     *                 .addSubcommand("cmd3sub3", new CommandLine(new GrandChild3Command3()) // deeper nesting
181     *                         .addSubcommand("cmd3sub3sub1", new GreatGrandChild3Command3_1())
182     *                         .addSubcommand("cmd3sub3sub2", new GreatGrandChild3Command3_2())
183     *                 )
184     *         );
185     * </pre>
186     * <p>The default type converters are available on all subcommands and nested sub-subcommands, but custom type
187     * converters are registered only with the subcommand hierarchy as it existed when the custom type was registered.
188     * To ensure a custom type converter is available to all subcommands, register the type converter last, after
189     * adding subcommands.</p>
190     * <p>See also the {@link Command#subcommands()} annotation to register subcommands declaratively.</p>
191     *
192     * @param name the string to recognize on the command line as a subcommand
193     * @param command the object to initialize with command line arguments following the subcommand name.
194     *          This may be a {@code CommandLine} instance with its own (nested) subcommands
195     * @return this CommandLine object, to allow method chaining
196     * @see #registerConverter(Class, ITypeConverter)
197     * @since 0.9.7
198     * @see Command#subcommands()
199     */
200    public CommandLine addSubcommand(final String name, final Object command) {
201        final CommandLine commandLine = toCommandLine(command);
202        commandLine.parent = this;
203        interpreter.commands.put(name, commandLine);
204        return this;
205    }
206    /** Returns a map with the subcommands {@linkplain #addSubcommand(String, Object) registered} on this instance.
207     * @return a map with the registered subcommands
208     * @since 0.9.7
209     */
210    public Map<String, CommandLine> getSubcommands() {
211        return new LinkedHashMap<>(interpreter.commands);
212    }
213    /**
214     * Returns the command that this is a subcommand of, or {@code null} if this is a top-level command.
215     * @return the command that this is a subcommand of, or {@code null} if this is a top-level command
216     * @see #addSubcommand(String, Object)
217     * @see Command#subcommands()
218     * @since 0.9.8
219     */
220    public CommandLine getParent() {
221        return parent;
222    }
223
224    /** Returns the annotated object that this {@code CommandLine} instance was constructed with.
225     * @param <T> the type of the variable that the return value is being assigned to
226     * @return the annotated object that this {@code CommandLine} instance was constructed with
227     * @since 0.9.7
228     */
229    public <T> T getCommand() {
230        return (T) interpreter.command;
231    }
232
233    /** Returns {@code true} if an option annotated with {@link Option#usageHelp()} was specified on the command line.
234     * @return whether the parser encountered an option annotated with {@link Option#usageHelp()}.
235     * @since 0.9.8 */
236    public boolean isUsageHelpRequested() { return usageHelpRequested; }
237
238    /** Returns {@code true} if an option annotated with {@link Option#versionHelp()} was specified on the command line.
239     * @return whether the parser encountered an option annotated with {@link Option#versionHelp()}.
240     * @since 0.9.8 */
241    public boolean isVersionHelpRequested() { return versionHelpRequested; }
242
243    /** Returns whether options for single-value fields can be specified multiple times on the command line.
244     * The default is {@code false} and a {@link OverwrittenOptionException} is thrown if this happens.
245     * When {@code true}, the last specified value is retained.
246     * @return {@code true} if options for single-value fields can be specified multiple times on the command line, {@code false} otherwise
247     * @since 0.9.7
248     */
249    public boolean isOverwrittenOptionsAllowed() {
250        return overwrittenOptionsAllowed;
251    }
252
253    /** Sets whether options for single-value fields can be specified multiple times on the command line without a {@link OverwrittenOptionException} being thrown.
254     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
255     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
256     * later will have the default setting. To ensure a setting is applied to all
257     * subcommands, call the setter last, after adding subcommands.</p>
258     * @param newValue the new setting
259     * @return this {@code CommandLine} object, to allow method chaining
260     * @since 0.9.7
261     */
262    public CommandLine setOverwrittenOptionsAllowed(final boolean newValue) {
263        this.overwrittenOptionsAllowed = newValue;
264        for (final CommandLine command : interpreter.commands.values()) {
265            command.setOverwrittenOptionsAllowed(newValue);
266        }
267        return this;
268    }
269
270    /** Returns whether the end user may specify arguments on the command line that are not matched to any option or parameter fields.
271     * The default is {@code false} and a {@link UnmatchedArgumentException} is thrown if this happens.
272     * When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method.
273     * @return {@code true} if the end use may specify unmatched arguments on the command line, {@code false} otherwise
274     * @see #getUnmatchedArguments()
275     * @since 0.9.7
276     */
277    public boolean isUnmatchedArgumentsAllowed() {
278        return unmatchedArgumentsAllowed;
279    }
280
281    /** Sets whether the end user may specify unmatched arguments on the command line without a {@link UnmatchedArgumentException} being thrown.
282     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
283     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
284     * later will have the default setting. To ensure a setting is applied to all
285     * subcommands, call the setter last, after adding subcommands.</p>
286     * @param newValue the new setting. When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method.
287     * @return this {@code CommandLine} object, to allow method chaining
288     * @since 0.9.7
289     * @see #getUnmatchedArguments()
290     */
291    public CommandLine setUnmatchedArgumentsAllowed(final boolean newValue) {
292        this.unmatchedArgumentsAllowed = newValue;
293        for (final CommandLine command : interpreter.commands.values()) {
294            command.setUnmatchedArgumentsAllowed(newValue);
295        }
296        return this;
297    }
298
299    /** Returns the list of unmatched command line arguments, if any.
300     * @return the list of unmatched command line arguments or an empty list
301     * @see #isUnmatchedArgumentsAllowed()
302     * @since 0.9.7
303     */
304    public List<String> getUnmatchedArguments() {
305        return unmatchedArguments;
306    }
307
308    /**
309     * <p>
310     * Convenience method that initializes the specified annotated object from the specified command line arguments.
311     * </p><p>
312     * This is equivalent to
313     * </p><pre>
314     * CommandLine cli = new CommandLine(command);
315     * cli.parse(args);
316     * return command;
317     * </pre>
318     *
319     * @param command the object to initialize. This object contains fields annotated with
320     *          {@code @Option} or {@code @Parameters}.
321     * @param args the command line arguments to parse
322     * @param <T> the type of the annotated object
323     * @return the specified annotated object
324     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
325     * @throws ParameterException if the specified command line arguments are invalid
326     * @since 0.9.7
327     */
328    public static <T> T populateCommand(final T command, final String... args) {
329        final CommandLine cli = toCommandLine(command);
330        cli.parse(args);
331        return command;
332    }
333
334    /** Parses the specified command line arguments and returns a list of {@code CommandLine} objects representing the
335     * top-level command and any subcommands (if any) that were recognized and initialized during the parsing process.
336     * <p>
337     * If parsing succeeds, the first element in the returned list is always {@code this CommandLine} object. The
338     * returned list may contain more elements if subcommands were {@linkplain #addSubcommand(String, Object) registered}
339     * and these subcommands were initialized by matching command line arguments. If parsing fails, a
340     * {@link ParameterException} is thrown.
341     * </p>
342     *
343     * @param args the command line arguments to parse
344     * @return a list with the top-level command and any subcommands initialized by this method
345     * @throws ParameterException if the specified command line arguments are invalid; use
346     *      {@link ParameterException#getCommandLine()} to get the command or subcommand whose user input was invalid
347     */
348    public List<CommandLine> parse(final String... args) {
349        return interpreter.parse(args);
350    }
351    /**
352     * Represents a function that can process a List of {@code CommandLine} objects resulting from successfully
353     * {@linkplain #parse(String...) parsing} the command line arguments. This is a
354     * <a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">functional interface</a>
355     * whose functional method is {@link #handleParseResult(List, PrintStream, CommandLine.Help.Ansi)}.
356     * <p>
357     * Implementations of this functions can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandler}
358     * methods to take some next step after the command line was successfully parsed.
359     * </p>
360     * @see RunFirst
361     * @see RunLast
362     * @see RunAll
363     * @since 2.0 */
364    public static interface IParseResultHandler {
365        /** Processes a List of {@code CommandLine} objects resulting from successfully
366         * {@linkplain #parse(String...) parsing} the command line arguments and optionally returns a list of results.
367         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
368         * @param out the {@code PrintStream} to print help to if requested
369         * @param ansi for printing help messages using ANSI styles and colors
370         * @return a list of results, or an empty list if there are no results
371         * @throws ExecutionException if a problem occurred while processing the parse results; use
372         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
373         */
374        List<Object> handleParseResult(List<CommandLine> parsedCommands, PrintStream out, Help.Ansi ansi) throws ExecutionException;
375    }
376    /**
377     * Represents a function that can handle a {@code ParameterException} that occurred while
378     * {@linkplain #parse(String...) parsing} the command line arguments. This is a
379     * <a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">functional interface</a>
380     * whose functional method is {@link #handleException(CommandLine.ParameterException, PrintStream, CommandLine.Help.Ansi, String...)}.
381     * <p>
382     * Implementations of this functions can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandler}
383     * methods to handle situations when the command line could not be parsed.
384     * </p>
385     * @see DefaultExceptionHandler
386     * @since 2.0 */
387    public static interface IExceptionHandler {
388        /** Handles a {@code ParameterException} that occurred while {@linkplain #parse(String...) parsing} the command
389         * line arguments and optionally returns a list of results.
390         * @param ex the ParameterException describing the problem that occurred while parsing the command line arguments,
391         *           and the CommandLine representing the command or subcommand whose input was invalid
392         * @param out the {@code PrintStream} to print help to if requested
393         * @param ansi for printing help messages using ANSI styles and colors
394         * @param args the command line arguments that could not be parsed
395         * @return a list of results, or an empty list if there are no results
396         */
397        List<Object> handleException(ParameterException ex, PrintStream out, Help.Ansi ansi, String... args);
398    }
399    /**
400     * Default exception handler that prints the exception message to the specified {@code PrintStream}, followed by the
401     * usage message for the command or subcommand whose input was invalid.
402     * <p>Implementation roughly looks like this:</p>
403     * <pre>
404     *     System.err.println(paramException.getMessage());
405     *     paramException.getCommandLine().usage(System.err);
406     * </pre>
407     * @since 2.0 */
408    public static class DefaultExceptionHandler implements IExceptionHandler {
409        @Override
410        public List<Object> handleException(final ParameterException ex, final PrintStream out, final Help.Ansi ansi, final String... args) {
411            out.println(ex.getMessage());
412            ex.getCommandLine().usage(out, ansi);
413            return Collections.emptyList();
414        }
415    }
416    /**
417     * Helper method that may be useful when processing the list of {@code CommandLine} objects that result from successfully
418     * {@linkplain #parse(String...) parsing} command line arguments. This method prints out
419     * {@linkplain #usage(PrintStream, Help.Ansi) usage help} if {@linkplain #isUsageHelpRequested() requested}
420     * or {@linkplain #printVersionHelp(PrintStream, Help.Ansi) version help} if {@linkplain #isVersionHelpRequested() requested}
421     * and returns {@code true}. Otherwise, if none of the specified {@code CommandLine} objects have help requested,
422     * this method returns {@code false}.
423     * <p>
424     * Note that this method <em>only</em> looks at the {@link Option#usageHelp() usageHelp} and
425     * {@link Option#versionHelp() versionHelp} attributes. The {@link Option#help() help} attribute is ignored.
426     * </p>
427     * @param parsedCommands the list of {@code CommandLine} objects to check if help was requested
428     * @param out the {@code PrintStream} to print help to if requested
429     * @param ansi for printing help messages using ANSI styles and colors
430     * @return {@code true} if help was printed, {@code false} otherwise
431     * @since 2.0 */
432    public static boolean printHelpIfRequested(final List<CommandLine> parsedCommands, final PrintStream out, final Help.Ansi ansi) {
433        for (final CommandLine parsed : parsedCommands) {
434            if (parsed.isUsageHelpRequested()) {
435                parsed.usage(out, ansi);
436                return true;
437            } else if (parsed.isVersionHelpRequested()) {
438                parsed.printVersionHelp(out, ansi);
439                return true;
440            }
441        }
442        return false;
443    }
444    private static Object execute(final CommandLine parsed) {
445        final Object command = parsed.getCommand();
446        if (command instanceof Runnable) {
447            try {
448                ((Runnable) command).run();
449                return null;
450            } catch (final Exception ex) {
451                throw new ExecutionException(parsed, "Error while running command (" + command + ")", ex);
452            }
453        } else if (command instanceof Callable) {
454            try {
455                return ((Callable<Object>) command).call();
456            } catch (final Exception ex) {
457                throw new ExecutionException(parsed, "Error while calling command (" + command + ")", ex);
458            }
459        }
460        throw new ExecutionException(parsed, "Parsed command (" + command + ") is not Runnable or Callable");
461    }
462    /**
463     * Command line parse result handler that prints help if requested, and otherwise executes the top-level
464     * {@code Runnable} or {@code Callable} command.
465     * For use in the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) parseWithHandler} methods.
466     * <p>
467     * From picocli v2.0, {@code RunFirst} is used to implement the {@link #run(Runnable, PrintStream, Help.Ansi, String...) run}
468     * and {@link #call(Callable, PrintStream, Help.Ansi, String...) call} convenience methods.
469     * </p>
470     * @since 2.0 */
471    public static class RunFirst implements IParseResultHandler {
472        /** Prints help if requested, and otherwise executes the top-level {@code Runnable} or {@code Callable} command.
473         * If the top-level command does not implement either {@code Runnable} or {@code Callable}, a {@code ExecutionException}
474         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
475         *
476         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
477         * @param out the {@code PrintStream} to print help to if requested
478         * @param ansi for printing help messages using ANSI styles and colors
479         * @return an empty list if help was requested, or a list containing a single element: the result of calling the
480         *      {@code Callable}, or a {@code null} element if the top-level command was a {@code Runnable}
481         * @throws ExecutionException if a problem occurred while processing the parse results; use
482         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
483         */
484        @Override
485        public List<Object> handleParseResult(final List<CommandLine> parsedCommands, final PrintStream out, final Help.Ansi ansi) {
486            if (printHelpIfRequested(parsedCommands, out, ansi)) { return Collections.emptyList(); }
487            return Arrays.asList(execute(parsedCommands.get(0)));
488        }
489    }
490    /**
491     * Command line parse result handler that prints help if requested, and otherwise executes the most specific
492     * {@code Runnable} or {@code Callable} subcommand.
493     * For use in the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) parseWithHandler} methods.
494     * <p>
495     * Something like this:</p>
496     * <pre>
497     *     // RunLast implementation: print help if requested, otherwise execute the most specific subcommand
498     *     if (CommandLine.printHelpIfRequested(parsedCommands, System.err, Help.Ansi.AUTO)) {
499     *         return emptyList();
500     *     }
501     *     CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
502     *     Object command = last.getCommand();
503     *     if (command instanceof Runnable) {
504     *         try {
505     *             ((Runnable) command).run();
506     *         } catch (Exception ex) {
507     *             throw new ExecutionException(last, "Error in runnable " + command, ex);
508     *         }
509     *     } else if (command instanceof Callable) {
510     *         Object result;
511     *         try {
512     *             result = ((Callable) command).call();
513     *         } catch (Exception ex) {
514     *             throw new ExecutionException(last, "Error in callable " + command, ex);
515     *         }
516     *         // ...do something with result
517     *     } else {
518     *         throw new ExecutionException(last, "Parsed command (" + command + ") is not Runnable or Callable");
519     *     }
520     * </pre>
521     * @since 2.0 */
522    public static class RunLast implements IParseResultHandler {
523        /** Prints help if requested, and otherwise executes the most specific {@code Runnable} or {@code Callable} subcommand.
524         * If the last (sub)command does not implement either {@code Runnable} or {@code Callable}, a {@code ExecutionException}
525         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
526         *
527         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
528         * @param out the {@code PrintStream} to print help to if requested
529         * @param ansi for printing help messages using ANSI styles and colors
530         * @return an empty list if help was requested, or a list containing a single element: the result of calling the
531         *      {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable}
532         * @throws ExecutionException if a problem occurred while processing the parse results; use
533         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
534         */
535        @Override
536        public List<Object> handleParseResult(final List<CommandLine> parsedCommands, final PrintStream out, final Help.Ansi ansi) {
537            if (printHelpIfRequested(parsedCommands, out, ansi)) { return Collections.emptyList(); }
538            final CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
539            return Arrays.asList(execute(last));
540        }
541    }
542    /**
543     * Command line parse result handler that prints help if requested, and otherwise executes the top-level command and
544     * all subcommands as {@code Runnable} or {@code Callable}.
545     * For use in the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) parseWithHandler} methods.
546     * @since 2.0 */
547    public static class RunAll implements IParseResultHandler {
548        /** Prints help if requested, and otherwise executes the top-level command and all subcommands as {@code Runnable}
549         * or {@code Callable}. If any of the {@code CommandLine} commands does not implement either
550         * {@code Runnable} or {@code Callable}, a {@code ExecutionException}
551         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
552         *
553         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
554         * @param out the {@code PrintStream} to print help to if requested
555         * @param ansi for printing help messages using ANSI styles and colors
556         * @return an empty list if help was requested, or a list containing the result of executing all commands:
557         *      the return values from calling the {@code Callable} commands, {@code null} elements for commands that implement {@code Runnable}
558         * @throws ExecutionException if a problem occurred while processing the parse results; use
559         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
560         */
561        @Override
562        public List<Object> handleParseResult(final List<CommandLine> parsedCommands, final PrintStream out, final Help.Ansi ansi) {
563            if (printHelpIfRequested(parsedCommands, out, ansi)) {
564                return null;
565            }
566            final List<Object> result = new ArrayList<>();
567            for (final CommandLine parsed : parsedCommands) {
568                result.add(execute(parsed));
569            }
570            return result;
571        }
572    }
573    /**
574     * Returns the result of calling {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...)}
575     * with {@code Help.Ansi.AUTO} and a new {@link DefaultExceptionHandler} in addition to the specified parse result handler,
576     * {@code PrintStream}, and the specified command line arguments.
577     * <p>
578     * This is a convenience method intended to offer the same ease of use as the {@link #run(Runnable, PrintStream, Help.Ansi, String...) run}
579     * and {@link #call(Callable, PrintStream, Help.Ansi, String...) call} methods, but with more flexibility and better
580     * support for nested subcommands.
581     * </p>
582     * <p>Calling this method roughly expands to:</p>
583     * <pre>
584     * try {
585     *     List&lt;CommandLine&gt; parsedCommands = parse(args);
586     *     return parseResultsHandler.handleParseResult(parsedCommands, out, Help.Ansi.AUTO);
587     * } catch (ParameterException ex) {
588     *     return new DefaultExceptionHandler().handleException(ex, out, ansi, args);
589     * }
590     * </pre>
591     * <p>
592     * Picocli provides some default handlers that allow you to accomplish some common tasks with very little code.
593     * The following handlers are available:</p>
594     * <ul>
595     *   <li>{@link RunLast} handler prints help if requested, and otherwise gets the last specified command or subcommand
596     * and tries to execute it as a {@code Runnable} or {@code Callable}.</li>
597     *   <li>{@link RunFirst} handler prints help if requested, and otherwise executes the top-level command as a {@code Runnable} or {@code Callable}.</li>
598     *   <li>{@link RunAll} handler prints help if requested, and otherwise executes all recognized commands and subcommands as {@code Runnable} or {@code Callable} tasks.</li>
599     *   <li>{@link DefaultExceptionHandler} prints the error message followed by usage help</li>
600     * </ul>
601     * @param handler the function that will process the result of successfully parsing the command line arguments
602     * @param out the {@code PrintStream} to print help to if requested
603     * @param args the command line arguments
604     * @return a list of results, or an empty list if there are no results
605     * @throws ExecutionException if the command line arguments were parsed successfully but a problem occurred while processing the
606     *      parse results; use {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
607     * @see RunLast
608     * @see RunAll
609     * @since 2.0 */
610    public List<Object> parseWithHandler(final IParseResultHandler handler, final PrintStream out, final String... args) {
611        return parseWithHandlers(handler, out, Help.Ansi.AUTO, new DefaultExceptionHandler(), args);
612    }
613    /**
614     * Tries to {@linkplain #parse(String...) parse} the specified command line arguments, and if successful, delegates
615     * the processing of the resulting list of {@code CommandLine} objects to the specified {@linkplain IParseResultHandler handler}.
616     * If the command line arguments were invalid, the {@code ParameterException} thrown from the {@code parse} method
617     * is caught and passed to the specified {@link IExceptionHandler}.
618     * <p>
619     * This is a convenience method intended to offer the same ease of use as the {@link #run(Runnable, PrintStream, Help.Ansi, String...) run}
620     * and {@link #call(Callable, PrintStream, Help.Ansi, String...) call} methods, but with more flexibility and better
621     * support for nested subcommands.
622     * </p>
623     * <p>Calling this method roughly expands to:</p>
624     * <pre>
625     * try {
626     *     List&lt;CommandLine&gt; parsedCommands = parse(args);
627     *     return parseResultsHandler.handleParseResult(parsedCommands, out, ansi);
628     * } catch (ParameterException ex) {
629     *     return new exceptionHandler.handleException(ex, out, ansi, args);
630     * }
631     * </pre>
632     * <p>
633     * Picocli provides some default handlers that allow you to accomplish some common tasks with very little code.
634     * The following handlers are available:</p>
635     * <ul>
636     *   <li>{@link RunLast} handler prints help if requested, and otherwise gets the last specified command or subcommand
637     * and tries to execute it as a {@code Runnable} or {@code Callable}.</li>
638     *   <li>{@link RunFirst} handler prints help if requested, and otherwise executes the top-level command as a {@code Runnable} or {@code Callable}.</li>
639     *   <li>{@link RunAll} handler prints help if requested, and otherwise executes all recognized commands and subcommands as {@code Runnable} or {@code Callable} tasks.</li>
640     *   <li>{@link DefaultExceptionHandler} prints the error message followed by usage help</li>
641     * </ul>
642     *
643     * @param handler the function that will process the result of successfully parsing the command line arguments
644     * @param out the {@code PrintStream} to print help to if requested
645     * @param ansi for printing help messages using ANSI styles and colors
646     * @param exceptionHandler the function that can handle the {@code ParameterException} thrown when the command line arguments are invalid
647     * @param args the command line arguments
648     * @return a list of results produced by the {@code IParseResultHandler} or the {@code IExceptionHandler}, or an empty list if there are no results
649     * @throws ExecutionException if the command line arguments were parsed successfully but a problem occurred while processing the parse
650     *      result {@code CommandLine} objects; use {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
651     * @see RunLast
652     * @see RunAll
653     * @see DefaultExceptionHandler
654     * @since 2.0 */
655    public List<Object> parseWithHandlers(final IParseResultHandler handler, final PrintStream out, final Help.Ansi ansi, final IExceptionHandler exceptionHandler, final String... args) {
656        try {
657            final List<CommandLine> result = parse(args);
658            return handler.handleParseResult(result, out, ansi);
659        } catch (final ParameterException ex) {
660            return exceptionHandler.handleException(ex, out, ansi, args);
661        }
662    }
663    /**
664     * Equivalent to {@code new CommandLine(command).usage(out)}. See {@link #usage(PrintStream)} for details.
665     * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters}
666     * @param out the print stream to print the help message to
667     * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
668     */
669    public static void usage(final Object command, final PrintStream out) {
670        toCommandLine(command).usage(out);
671    }
672
673    /**
674     * Equivalent to {@code new CommandLine(command).usage(out, ansi)}.
675     * See {@link #usage(PrintStream, Help.Ansi)} for details.
676     * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters}
677     * @param out the print stream to print the help message to
678     * @param ansi whether the usage message should contain ANSI escape codes or not
679     * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
680     */
681    public static void usage(final Object command, final PrintStream out, final Help.Ansi ansi) {
682        toCommandLine(command).usage(out, ansi);
683    }
684
685    /**
686     * Equivalent to {@code new CommandLine(command).usage(out, colorScheme)}.
687     * See {@link #usage(PrintStream, Help.ColorScheme)} for details.
688     * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters}
689     * @param out the print stream to print the help message to
690     * @param colorScheme the {@code ColorScheme} defining the styles for options, parameters and commands when ANSI is enabled
691     * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
692     */
693    public static void usage(final Object command, final PrintStream out, final Help.ColorScheme colorScheme) {
694        toCommandLine(command).usage(out, colorScheme);
695    }
696
697    /**
698     * Delegates to {@link #usage(PrintStream, Help.Ansi)} with the {@linkplain Help.Ansi#AUTO platform default}.
699     * @param out the printStream to print to
700     * @see #usage(PrintStream, Help.ColorScheme)
701     */
702    public void usage(final PrintStream out) {
703        usage(out, Help.Ansi.AUTO);
704    }
705
706    /**
707     * Delegates to {@link #usage(PrintStream, Help.ColorScheme)} with the {@linkplain Help#defaultColorScheme(CommandLine.Help.Ansi) default color scheme}.
708     * @param out the printStream to print to
709     * @param ansi whether the usage message should include ANSI escape codes or not
710     * @see #usage(PrintStream, Help.ColorScheme)
711     */
712    public void usage(final PrintStream out, final Help.Ansi ansi) {
713        usage(out, Help.defaultColorScheme(ansi));
714    }
715    /**
716     * Prints a usage help message for the annotated command class to the specified {@code PrintStream}.
717     * Delegates construction of the usage help message to the {@link Help} inner class and is equivalent to:
718     * <pre>
719     * Help help = new Help(command).addAllSubcommands(getSubcommands());
720     * StringBuilder sb = new StringBuilder()
721     *         .append(help.headerHeading())
722     *         .append(help.header())
723     *         .append(help.synopsisHeading())      //e.g. Usage:
724     *         .append(help.synopsis())             //e.g. &lt;main class&gt; [OPTIONS] &lt;command&gt; [COMMAND-OPTIONS] [ARGUMENTS]
725     *         .append(help.descriptionHeading())   //e.g. %nDescription:%n%n
726     *         .append(help.description())          //e.g. {"Converts foos to bars.", "Use options to control conversion mode."}
727     *         .append(help.parameterListHeading()) //e.g. %nPositional parameters:%n%n
728     *         .append(help.parameterList())        //e.g. [FILE...] the files to convert
729     *         .append(help.optionListHeading())    //e.g. %nOptions:%n%n
730     *         .append(help.optionList())           //e.g. -h, --help   displays this help and exits
731     *         .append(help.commandListHeading())   //e.g. %nCommands:%n%n
732     *         .append(help.commandList())          //e.g.    add       adds the frup to the frooble
733     *         .append(help.footerHeading())
734     *         .append(help.footer());
735     * out.print(sb);
736     * </pre>
737     * <p>Annotate your class with {@link Command} to control many aspects of the usage help message, including
738     * the program name, text of section headings and section contents, and some aspects of the auto-generated sections
739     * of the usage help message.
740     * <p>To customize the auto-generated sections of the usage help message, like how option details are displayed,
741     * instantiate a {@link Help} object and use a {@link Help.TextTable} with more of fewer columns, a custom
742     * {@linkplain Help.Layout layout}, and/or a custom option {@linkplain Help.IOptionRenderer renderer}
743     * for ultimate control over which aspects of an Option or Field are displayed where.</p>
744     * @param out the {@code PrintStream} to print the usage help message to
745     * @param colorScheme the {@code ColorScheme} defining the styles for options, parameters and commands when ANSI is enabled
746     */
747    public void usage(final PrintStream out, final Help.ColorScheme colorScheme) {
748        final Help help = new Help(interpreter.command, colorScheme).addAllSubcommands(getSubcommands());
749        if (!Help.DEFAULT_SEPARATOR.equals(getSeparator())) {
750            help.separator = getSeparator();
751            help.parameterLabelRenderer = help.createDefaultParamLabelRenderer(); // update for new separator
752        }
753        if (!Help.DEFAULT_COMMAND_NAME.equals(getCommandName())) {
754            help.commandName = getCommandName();
755        }
756        final StringBuilder sb = new StringBuilder()
757                .append(help.headerHeading())
758                .append(help.header())
759                .append(help.synopsisHeading())      //e.g. Usage:
760                .append(help.synopsis(help.synopsisHeadingLength())) //e.g. &lt;main class&gt; [OPTIONS] &lt;command&gt; [COMMAND-OPTIONS] [ARGUMENTS]
761                .append(help.descriptionHeading())   //e.g. %nDescription:%n%n
762                .append(help.description())          //e.g. {"Converts foos to bars.", "Use options to control conversion mode."}
763                .append(help.parameterListHeading()) //e.g. %nPositional parameters:%n%n
764                .append(help.parameterList())        //e.g. [FILE...] the files to convert
765                .append(help.optionListHeading())    //e.g. %nOptions:%n%n
766                .append(help.optionList())           //e.g. -h, --help   displays this help and exits
767                .append(help.commandListHeading())   //e.g. %nCommands:%n%n
768                .append(help.commandList())          //e.g.    add       adds the frup to the frooble
769                .append(help.footerHeading())
770                .append(help.footer());
771        out.print(sb);
772    }
773
774    /**
775     * Delegates to {@link #printVersionHelp(PrintStream, Help.Ansi)} with the {@linkplain Help.Ansi#AUTO platform default}.
776     * @param out the printStream to print to
777     * @see #printVersionHelp(PrintStream, Help.Ansi)
778     * @since 0.9.8
779     */
780    public void printVersionHelp(final PrintStream out) { printVersionHelp(out, Help.Ansi.AUTO); }
781
782    /**
783     * Prints version information from the {@link Command#version()} annotation to the specified {@code PrintStream}.
784     * Each element of the array of version strings is printed on a separate line. Version strings may contain
785     * <a href="http://picocli.info/#_usage_help_with_styles_and_colors">markup for colors and style</a>.
786     * @param out the printStream to print to
787     * @param ansi whether the usage message should include ANSI escape codes or not
788     * @see Command#version()
789     * @see Option#versionHelp()
790     * @see #isVersionHelpRequested()
791     * @since 0.9.8
792     */
793    public void printVersionHelp(final PrintStream out, final Help.Ansi ansi) {
794        for (final String versionInfo : versionLines) {
795            out.println(ansi.new Text(versionInfo));
796        }
797    }
798    /**
799     * Prints version information from the {@link Command#version()} annotation to the specified {@code PrintStream}.
800     * Each element of the array of version strings is {@linkplain String#format(String, Object...) formatted} with the
801     * specified parameters, and printed on a separate line. Both version strings and parameters may contain
802     * <a href="http://picocli.info/#_usage_help_with_styles_and_colors">markup for colors and style</a>.
803     * @param out the printStream to print to
804     * @param ansi whether the usage message should include ANSI escape codes or not
805     * @param params Arguments referenced by the format specifiers in the version strings
806     * @see Command#version()
807     * @see Option#versionHelp()
808     * @see #isVersionHelpRequested()
809     * @since 1.0.0
810     */
811    public void printVersionHelp(final PrintStream out, final Help.Ansi ansi, final Object... params) {
812        for (final String versionInfo : versionLines) {
813            out.println(ansi.new Text(String.format(versionInfo, params)));
814        }
815    }
816
817    /**
818     * Delegates to {@link #call(Callable, PrintStream, Help.Ansi, String...)} with {@link Help.Ansi#AUTO}.
819     * <p>
820     * From picocli v2.0, this method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, Help.Ansi) requested},
821     * and any exceptions thrown by the {@code Callable} are caught and rethrown wrapped in an {@code ExecutionException}.
822     * </p>
823     * @param callable the command to call when {@linkplain #parse(String...) parsing} succeeds.
824     * @param out the printStream to print to
825     * @param args the command line arguments to parse
826     * @param <C> the annotated object must implement Callable
827     * @param <T> the return type of the most specific command (must implement {@code Callable})
828     * @see #call(Callable, PrintStream, Help.Ansi, String...)
829     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
830     * @throws ExecutionException if the Callable throws an exception
831     * @return {@code null} if an error occurred while parsing the command line options, otherwise returns the result of calling the Callable
832     * @see #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...)
833     * @see RunFirst
834     */
835    public static <C extends Callable<T>, T> T call(final C callable, final PrintStream out, final String... args) {
836        return call(callable, out, Help.Ansi.AUTO, args);
837    }
838    /**
839     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
840     * The annotated object needs to implement {@link Callable}. Calling this method is equivalent to:
841     * <pre>
842     * CommandLine cmd = new CommandLine(callable);
843     * List&lt;CommandLine&gt; parsedCommands;
844     * try {
845     *     parsedCommands = cmd.parse(args);
846     * } catch (ParameterException ex) {
847     *     out.println(ex.getMessage());
848     *     cmd.usage(out, ansi);
849     *     return null;
850     * }
851     * if (CommandLine.printHelpIfRequested(parsedCommands, out, ansi)) {
852     *     return null;
853     * }
854     * CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
855     * try {
856     *     Callable&lt;Object&gt; subcommand = last.getCommand();
857     *     return subcommand.call();
858     * } catch (Exception ex) {
859     *     throw new ExecutionException(last, "Error calling " + last.getCommand(), ex);
860     * }
861     * </pre>
862     * <p>
863     * If the specified Callable command has subcommands, the {@linkplain RunLast last} subcommand specified on the
864     * command line is executed.
865     * Commands with subcommands may be interested in calling the {@link #parseWithHandler(IParseResultHandler, PrintStream, String...) parseWithHandler}
866     * method with a {@link RunAll} handler or a custom handler.
867     * </p><p>
868     * From picocli v2.0, this method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, Help.Ansi) requested},
869     * and any exceptions thrown by the {@code Callable} are caught and rethrown wrapped in an {@code ExecutionException}.
870     * </p>
871     * @param callable the command to call when {@linkplain #parse(String...) parsing} succeeds.
872     * @param out the printStream to print to
873     * @param ansi whether the usage message should include ANSI escape codes or not
874     * @param args the command line arguments to parse
875     * @param <C> the annotated object must implement Callable
876     * @param <T> the return type of the specified {@code Callable}
877     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
878     * @throws ExecutionException if the Callable throws an exception
879     * @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
880     * @see #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...)
881     * @see RunLast
882     */
883    public static <C extends Callable<T>, T> T call(final C callable, final PrintStream out, final Help.Ansi ansi, final String... args) {
884        final CommandLine cmd = new CommandLine(callable); // validate command outside of try-catch
885        final List<Object> results = cmd.parseWithHandlers(new RunLast(), out, ansi, new DefaultExceptionHandler(), args);
886        return results == null || results.isEmpty() ? null : (T) results.get(0);
887    }
888
889    /**
890     * Delegates to {@link #run(Runnable, PrintStream, Help.Ansi, String...)} with {@link Help.Ansi#AUTO}.
891     * <p>
892     * From picocli v2.0, this method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, Help.Ansi) requested},
893     * and any exceptions thrown by the {@code Runnable} are caught and rethrown wrapped in an {@code ExecutionException}.
894     * </p>
895     * @param runnable the command to run when {@linkplain #parse(String...) parsing} succeeds.
896     * @param out the printStream to print to
897     * @param args the command line arguments to parse
898     * @param <R> the annotated object must implement Runnable
899     * @see #run(Runnable, PrintStream, Help.Ansi, String...)
900     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
901     * @throws ExecutionException if the Runnable throws an exception
902     * @see #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...)
903     * @see RunFirst
904     */
905    public static <R extends Runnable> void run(final R runnable, final PrintStream out, final String... args) {
906        run(runnable, out, Help.Ansi.AUTO, args);
907    }
908    /**
909     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
910     * The annotated object needs to implement {@link Runnable}. Calling this method is equivalent to:
911     * <pre>
912     * CommandLine cmd = new CommandLine(runnable);
913     * List&lt;CommandLine&gt; parsedCommands;
914     * try {
915     *     parsedCommands = cmd.parse(args);
916     * } catch (ParameterException ex) {
917     *     out.println(ex.getMessage());
918     *     cmd.usage(out, ansi);
919     *     return null;
920     * }
921     * if (CommandLine.printHelpIfRequested(parsedCommands, out, ansi)) {
922     *     return null;
923     * }
924     * CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
925     * try {
926     *     Runnable subcommand = last.getCommand();
927     *     subcommand.run();
928     * } catch (Exception ex) {
929     *     throw new ExecutionException(last, "Error running " + last.getCommand(), ex);
930     * }
931     * </pre>
932     * <p>
933     * If the specified Runnable command has subcommands, the {@linkplain RunLast last} subcommand specified on the
934     * command line is executed.
935     * Commands with subcommands may be interested in calling the {@link #parseWithHandler(IParseResultHandler, PrintStream, String...) parseWithHandler}
936     * method with a {@link RunAll} handler or a custom handler.
937     * </p><p>
938     * From picocli v2.0, this method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, Help.Ansi) requested},
939     * and any exceptions thrown by the {@code Runnable} are caught and rethrown wrapped in an {@code ExecutionException}.
940     * </p>
941     * @param runnable the command to run when {@linkplain #parse(String...) parsing} succeeds.
942     * @param out the printStream to print to
943     * @param ansi whether the usage message should include ANSI escape codes or not
944     * @param args the command line arguments to parse
945     * @param <R> the annotated object must implement Runnable
946     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
947     * @throws ExecutionException if the Runnable throws an exception
948     * @see #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...)
949     * @see RunLast
950     */
951    public static <R extends Runnable> void run(final R runnable, final PrintStream out, final Help.Ansi ansi, final String... args) {
952        final CommandLine cmd = new CommandLine(runnable); // validate command outside of try-catch
953        cmd.parseWithHandlers(new RunLast(), out, ansi, new DefaultExceptionHandler(), args);
954    }
955
956    /**
957     * Registers the specified type converter for the specified class. When initializing fields annotated with
958     * {@link Option}, the field's type is used as a lookup key to find the associated type converter, and this
959     * type converter converts the original command line argument string value to the correct type.
960     * <p>
961     * Java 8 lambdas make it easy to register custom type converters:
962     * </p>
963     * <pre>
964     * commandLine.registerConverter(java.nio.file.Path.class, s -&gt; java.nio.file.Paths.get(s));
965     * commandLine.registerConverter(java.time.Duration.class, s -&gt; java.time.Duration.parse(s));</pre>
966     * <p>
967     * Built-in type converters are pre-registered for the following java 1.5 types:
968     * </p>
969     * <ul>
970     *   <li>all primitive types</li>
971     *   <li>all primitive wrapper types: Boolean, Byte, Character, Double, Float, Integer, Long, Short</li>
972     *   <li>any enum</li>
973     *   <li>java.io.File</li>
974     *   <li>java.math.BigDecimal</li>
975     *   <li>java.math.BigInteger</li>
976     *   <li>java.net.InetAddress</li>
977     *   <li>java.net.URI</li>
978     *   <li>java.net.URL</li>
979     *   <li>java.nio.charset.Charset</li>
980     *   <li>java.sql.Time</li>
981     *   <li>java.util.Date</li>
982     *   <li>java.util.UUID</li>
983     *   <li>java.util.regex.Pattern</li>
984     *   <li>StringBuilder</li>
985     *   <li>CharSequence</li>
986     *   <li>String</li>
987     * </ul>
988     * <p>The specified converter will be registered with this {@code CommandLine} and the full hierarchy of its
989     * subcommands and nested sub-subcommands <em>at the moment the converter is registered</em>. Subcommands added
990     * later will not have this converter added automatically. To ensure a custom type converter is available to all
991     * subcommands, register the type converter last, after adding subcommands.</p>
992     *
993     * @param cls the target class to convert parameter string values to
994     * @param converter the class capable of converting string values to the specified target type
995     * @param <K> the target type
996     * @return this CommandLine object, to allow method chaining
997     * @see #addSubcommand(String, Object)
998     */
999    public <K> CommandLine registerConverter(final Class<K> cls, final ITypeConverter<K> converter) {
1000        interpreter.converterRegistry.put(Assert.notNull(cls, "class"), Assert.notNull(converter, "converter"));
1001        for (final CommandLine command : interpreter.commands.values()) {
1002            command.registerConverter(cls, converter);
1003        }
1004        return this;
1005    }
1006
1007    /** Returns the String that separates option names from option values when parsing command line options. {@value Help#DEFAULT_SEPARATOR} by default.
1008     * @return the String the parser uses to separate option names from option values */
1009    public String getSeparator() {
1010        return interpreter.separator;
1011    }
1012
1013    /** Sets the String the parser uses to separate option names from option values to the specified value.
1014     * The separator may also be set declaratively with the {@link CommandLine.Command#separator()} annotation attribute.
1015     * @param separator the String that separates option names from option values
1016     * @return this {@code CommandLine} object, to allow method chaining */
1017    public CommandLine setSeparator(final String separator) {
1018        interpreter.separator = Assert.notNull(separator, "separator");
1019        return this;
1020    }
1021
1022    /** Returns the command name (also called program name) displayed in the usage help synopsis. {@value Help#DEFAULT_COMMAND_NAME} by default.
1023     * @return the command name (also called program name) displayed in the usage */
1024    public String getCommandName() {
1025        return commandName;
1026    }
1027
1028    /** Sets the command name (also called program name) displayed in the usage help synopsis to the specified value.
1029     * Note that this method only modifies the usage help message, it does not impact parsing behaviour.
1030     * The command name may also be set declaratively with the {@link CommandLine.Command#name()} annotation attribute.
1031     * @param commandName command name (also called program name) displayed in the usage help synopsis
1032     * @return this {@code CommandLine} object, to allow method chaining */
1033    public CommandLine setCommandName(final String commandName) {
1034        this.commandName = Assert.notNull(commandName, "commandName");
1035        return this;
1036    }
1037    private static boolean empty(final String str) { return str == null || str.trim().length() == 0; }
1038    private static boolean empty(final Object[] array) { return array == null || array.length == 0; }
1039    private static boolean empty(final Text txt) { return txt == null || txt.plain.toString().trim().length() == 0; }
1040    private static String str(final String[] arr, final int i) { return (arr == null || arr.length == 0) ? "" : arr[i]; }
1041    private static boolean isBoolean(final Class<?> type) { return type == Boolean.class || type == Boolean.TYPE; }
1042    private static CommandLine toCommandLine(final Object obj) { return obj instanceof CommandLine ? (CommandLine) obj : new CommandLine(obj);}
1043    private static boolean isMultiValue(final Field field) {  return isMultiValue(field.getType()); }
1044    private static boolean isMultiValue(final Class<?> cls) { return cls.isArray() || Collection.class.isAssignableFrom(cls) || Map.class.isAssignableFrom(cls); }
1045    private static Class<?>[] getTypeAttribute(final Field field) {
1046        final Class<?>[] explicit = field.isAnnotationPresent(Parameters.class) ? field.getAnnotation(Parameters.class).type() : field.getAnnotation(Option.class).type();
1047        if (explicit.length > 0) { return explicit; }
1048        if (field.getType().isArray()) { return new Class<?>[] { field.getType().getComponentType() }; }
1049        if (isMultiValue(field)) {
1050            final Type type = field.getGenericType(); // e.g. Map<Long, ? extends Number>
1051            if (type instanceof ParameterizedType) {
1052                final ParameterizedType parameterizedType = (ParameterizedType) type;
1053                final Type[] paramTypes = parameterizedType.getActualTypeArguments(); // e.g. ? extends Number
1054                final Class<?>[] result = new Class<?>[paramTypes.length];
1055                for (int i = 0; i < paramTypes.length; i++) {
1056                    if (paramTypes[i] instanceof Class) { result[i] = (Class<?>) paramTypes[i]; continue; } // e.g. Long
1057                    if (paramTypes[i] instanceof WildcardType) { // e.g. ? extends Number
1058                        final WildcardType wildcardType = (WildcardType) paramTypes[i];
1059                        final Type[] lower = wildcardType.getLowerBounds(); // e.g. []
1060                        if (lower.length > 0 && lower[0] instanceof Class) { result[i] = (Class<?>) lower[0]; continue; }
1061                        final Type[] upper = wildcardType.getUpperBounds(); // e.g. Number
1062                        if (upper.length > 0 && upper[0] instanceof Class) { result[i] = (Class<?>) upper[0]; continue; }
1063                    }
1064                    Arrays.fill(result, String.class); return result; // too convoluted generic type, giving up
1065                }
1066                return result; // we inferred all types from ParameterizedType
1067            }
1068            return new Class<?>[] {String.class, String.class}; // field is multi-value but not ParameterizedType
1069        }
1070        return new Class<?>[] {field.getType()}; // not a multi-value field
1071    }
1072    /**
1073     * <p>
1074     * Annotate fields in your class with {@code @Option} and picocli will initialize these fields when matching
1075     * arguments are specified on the command line.
1076     * </p><p>
1077     * For example:
1078     * </p>
1079     * <pre>import static picocli.CommandLine.*;
1080     *
1081     * public class MyClass {
1082     *     &#064;Parameters(type = File.class, description = "Any number of input files")
1083     *     private List&lt;File&gt; files = new ArrayList&lt;File&gt;();
1084     *
1085     *     &#064;Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
1086     *     private File outputFile;
1087     *
1088     *     &#064;Option(names = { "-v", "--verbose"}, description = "Verbosely list files processed")
1089     *     private boolean verbose;
1090     *
1091     *     &#064;Option(names = { "-h", "--help", "-?", "-help"}, usageHelp = true, description = "Display this help and exit")
1092     *     private boolean help;
1093     *
1094     *     &#064;Option(names = { "-V", "--version"}, versionHelp = true, description = "Display version information and exit")
1095     *     private boolean version;
1096     * }
1097     * </pre>
1098     * <p>
1099     * A field cannot be annotated with both {@code @Parameters} and {@code @Option} or a
1100     * {@code ParameterException} is thrown.
1101     * </p>
1102     */
1103    @Retention(RetentionPolicy.RUNTIME)
1104    @Target(ElementType.FIELD)
1105    public @interface Option {
1106        /**
1107         * One or more option names. At least one option name is required.
1108         * <p>
1109         * Different environments have different conventions for naming options, but usually options have a prefix
1110         * that sets them apart from parameters.
1111         * Picocli supports all of the below styles. The default separator is {@code '='}, but this can be configured.
1112         * </p><p>
1113         * <b>*nix</b>
1114         * </p><p>
1115         * In Unix and Linux, options have a short (single-character) name, a long name or both.
1116         * Short options
1117         * (<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02">POSIX
1118         * style</a> are single-character and are preceded by the {@code '-'} character, e.g., {@code `-v'}.
1119         * <a href="https://www.gnu.org/software/tar/manual/html_node/Long-Options.html">GNU-style</a> long
1120         * (or <em>mnemonic</em>) options start with two dashes in a row, e.g., {@code `--file'}.
1121         * </p><p>Picocli supports the POSIX convention that short options can be grouped, with the last option
1122         * optionally taking a parameter, which may be attached to the option name or separated by a space or
1123         * a {@code '='} character. The below examples are all equivalent:
1124         * </p><pre>
1125         * -xvfFILE
1126         * -xvf FILE
1127         * -xvf=FILE
1128         * -xv --file FILE
1129         * -xv --file=FILE
1130         * -x -v --file FILE
1131         * -x -v --file=FILE
1132         * </pre><p>
1133         * <b>DOS</b>
1134         * </p><p>
1135         * DOS options mostly have upper case single-character names and start with a single slash {@code '/'} character.
1136         * Option parameters are separated by a {@code ':'} character. Options cannot be grouped together but
1137         * must be specified separately. For example:
1138         * </p><pre>
1139         * DIR /S /A:D /T:C
1140         * </pre><p>
1141         * <b>PowerShell</b>
1142         * </p><p>
1143         * Windows PowerShell options generally are a word preceded by a single {@code '-'} character, e.g., {@code `-Help'}.
1144         * Option parameters are separated by a space or by a {@code ':'} character.
1145         * </p>
1146         * @return one or more option names
1147         */
1148        String[] names();
1149
1150        /**
1151         * Indicates whether this option is required. By default this is false.
1152         * If an option is required, but a user invokes the program without specifying the required option,
1153         * a {@link MissingParameterException} is thrown from the {@link #parse(String...)} method.
1154         * @return whether this option is required
1155         */
1156        boolean required() default false;
1157
1158        /**
1159         * Set {@code help=true} if this option should disable validation of the remaining arguments:
1160         * If the {@code help} option is specified, no error message is generated for missing required options.
1161         * <p>
1162         * This attribute is useful for special options like help ({@code -h} and {@code --help} on unix,
1163         * {@code -?} and {@code -Help} on Windows) or version ({@code -V} and {@code --version} on unix,
1164         * {@code -Version} on Windows).
1165         * </p>
1166         * <p>
1167         * Note that the {@link #parse(String...)} method will not print help documentation. It will only set
1168         * the value of the annotated field. It is the responsibility of the caller to inspect the annotated fields
1169         * and take the appropriate action.
1170         * </p>
1171         * @return whether this option disables validation of the other arguments
1172         * @deprecated Use {@link #usageHelp()} and {@link #versionHelp()} instead. See {@link #printHelpIfRequested(List, PrintStream, CommandLine.Help.Ansi)}
1173         */
1174        boolean help() default false;
1175
1176        /**
1177         * Set {@code usageHelp=true} if this option allows the user to request usage help. If this option is
1178         * specified on the command line, picocli will not validate the remaining arguments (so no "missing required
1179         * option" errors) and the {@link CommandLine#isUsageHelpRequested()} method will return {@code true}.
1180         * <p>
1181         * This attribute is useful for special options like help ({@code -h} and {@code --help} on unix,
1182         * {@code -?} and {@code -Help} on Windows).
1183         * </p>
1184         * <p>
1185         * Note that the {@link #parse(String...)} method will not print usage help documentation. It will only set
1186         * the value of the annotated field. It is the responsibility of the caller to inspect the annotated fields
1187         * and take the appropriate action.
1188         * </p>
1189         * @return whether this option allows the user to request usage help
1190         * @since 0.9.8
1191         */
1192        boolean usageHelp() default false;
1193
1194        /**
1195         * Set {@code versionHelp=true} if this option allows the user to request version information. If this option is
1196         * specified on the command line, picocli will not validate the remaining arguments (so no "missing required
1197         * option" errors) and the {@link CommandLine#isVersionHelpRequested()} method will return {@code true}.
1198         * <p>
1199         * This attribute is useful for special options like version ({@code -V} and {@code --version} on unix,
1200         * {@code -Version} on Windows).
1201         * </p>
1202         * <p>
1203         * Note that the {@link #parse(String...)} method will not print version information. It will only set
1204         * the value of the annotated field. It is the responsibility of the caller to inspect the annotated fields
1205         * and take the appropriate action.
1206         * </p>
1207         * @return whether this option allows the user to request version information
1208         * @since 0.9.8
1209         */
1210        boolean versionHelp() default false;
1211
1212        /**
1213         * Description of this option, used when generating the usage documentation.
1214         * @return the description of this option
1215         */
1216        String[] description() default {};
1217
1218        /**
1219         * Specifies the minimum number of required parameters and the maximum number of accepted parameters.
1220         * If an option declares a positive arity, and the user specifies an insufficient number of parameters on the
1221         * command line, a {@link MissingParameterException} is thrown by the {@link #parse(String...)} method.
1222         * <p>
1223         * In many cases picocli can deduce the number of required parameters from the field's type.
1224         * By default, flags (boolean options) have arity zero,
1225         * and single-valued type fields (String, int, Integer, double, Double, File, Date, etc) have arity one.
1226         * Generally, fields with types that cannot hold multiple values can omit the {@code arity} attribute.
1227         * </p><p>
1228         * Fields used to capture options with arity two or higher should have a type that can hold multiple values,
1229         * like arrays or Collections. See {@link #type()} for strongly-typed Collection fields.
1230         * </p><p>
1231         * For example, if an option has 2 required parameters and any number of optional parameters,
1232         * specify {@code @Option(names = "-example", arity = "2..*")}.
1233         * </p>
1234         * <b>A note on boolean options</b>
1235         * <p>
1236         * By default picocli does not expect boolean options (also called "flags" or "switches") to have a parameter.
1237         * You can make a boolean option take a required parameter by annotating your field with {@code arity="1"}.
1238         * For example: </p>
1239         * <pre>&#064;Option(names = "-v", arity = "1") boolean verbose;</pre>
1240         * <p>
1241         * Because this boolean field is defined with arity 1, the user must specify either {@code <program> -v false}
1242         * or {@code <program> -v true}
1243         * on the command line, or a {@link MissingParameterException} is thrown by the {@link #parse(String...)}
1244         * method.
1245         * </p><p>
1246         * To make the boolean parameter possible but optional, define the field with {@code arity = "0..1"}.
1247         * For example: </p>
1248         * <pre>&#064;Option(names="-v", arity="0..1") boolean verbose;</pre>
1249         * <p>This will accept any of the below without throwing an exception:</p>
1250         * <pre>
1251         * -v
1252         * -v true
1253         * -v false
1254         * </pre>
1255         * @return how many arguments this option requires
1256         */
1257        String arity() default "";
1258
1259        /**
1260         * Specify a {@code paramLabel} for the option parameter to be used in the usage help message. If omitted,
1261         * picocli uses the field name in fish brackets ({@code '<'} and {@code '>'}) by default. Example:
1262         * <pre>class Example {
1263         *     &#064;Option(names = {"-o", "--output"}, paramLabel="FILE", description="path of the output file")
1264         *     private File out;
1265         *     &#064;Option(names = {"-j", "--jobs"}, arity="0..1", description="Allow N jobs at once; infinite jobs with no arg.")
1266         *     private int maxJobs = -1;
1267         * }</pre>
1268         * <p>By default, the above gives a usage help message like the following:</p><pre>
1269         * Usage: &lt;main class&gt; [OPTIONS]
1270         * -o, --output FILE       path of the output file
1271         * -j, --jobs [&lt;maxJobs&gt;]  Allow N jobs at once; infinite jobs with no arg.
1272         * </pre>
1273         * @return name of the option parameter used in the usage help message
1274         */
1275        String paramLabel() default "";
1276
1277        /** <p>
1278         * Optionally specify a {@code type} to control exactly what Class the option parameter should be converted
1279         * to. This may be useful when the field type is an interface or an abstract class. For example, a field can
1280         * be declared to have type {@code java.lang.Number}, and annotating {@code @Option(type=Short.class)}
1281         * ensures that the option parameter value is converted to a {@code Short} before setting the field value.
1282         * </p><p>
1283         * For array fields whose <em>component</em> type is an interface or abstract class, specify the concrete <em>component</em> type.
1284         * For example, a field with type {@code Number[]} may be annotated with {@code @Option(type=Short.class)}
1285         * to ensure that option parameter values are converted to {@code Short} before adding an element to the array.
1286         * </p><p>
1287         * Picocli will use the {@link ITypeConverter} that is
1288         * {@linkplain #registerConverter(Class, ITypeConverter) registered} for the specified type to convert
1289         * the raw String values before modifying the field value.
1290         * </p><p>
1291         * Prior to 2.0, the {@code type} attribute was necessary for {@code Collection} and {@code Map} fields,
1292         * but starting from 2.0 picocli will infer the component type from the generic type's type arguments.
1293         * For example, for a field of type {@code Map<TimeUnit, Long>} picocli will know the option parameter
1294         * should be split up in key=value pairs, where the key should be converted to a {@code java.util.concurrent.TimeUnit}
1295         * enum value, and the value should be converted to a {@code Long}. No {@code @Option(type=...)} type attribute
1296         * is required for this. For generic types with wildcards, picocli will take the specified upper or lower bound
1297         * as the Class to convert to, unless the {@code @Option} annotation specifies an explicit {@code type} attribute.
1298         * </p><p>
1299         * If the field type is a raw collection or a raw map, and you want it to contain other values than Strings,
1300         * or if the generic type's type arguments are interfaces or abstract classes, you may
1301         * specify a {@code type} attribute to control the Class that the option parameter should be converted to.
1302         * @return the type(s) to convert the raw String values
1303         */
1304        Class<?>[] type() default {};
1305
1306        /**
1307         * Specify a regular expression to use to split option parameter values before applying them to the field.
1308         * All elements resulting from the split are added to the array or Collection. Ignored for single-value fields.
1309         * @return a regular expression to split option parameter values or {@code ""} if the value should not be split
1310         * @see String#split(String)
1311         */
1312        String split() default "";
1313
1314        /**
1315         * Set {@code hidden=true} if this option should not be included in the usage documentation.
1316         * @return whether this option should be excluded from the usage message
1317         */
1318        boolean hidden() default false;
1319    }
1320    /**
1321     * <p>
1322     * Fields annotated with {@code @Parameters} will be initialized with positional parameters. By specifying the
1323     * {@link #index()} attribute you can pick which (or what range) of the positional parameters to apply. If no index
1324     * is specified, the field will get all positional parameters (so it should be an array or a collection).
1325     * </p><p>
1326     * When parsing the command line arguments, picocli first tries to match arguments to {@link Option Options}.
1327     * Positional parameters are the arguments that follow the options, or the arguments that follow a "--" (double
1328     * dash) argument on the command line.
1329     * </p><p>
1330     * For example:
1331     * </p>
1332     * <pre>import static picocli.CommandLine.*;
1333     *
1334     * public class MyCalcParameters {
1335     *     &#064;Parameters(type = BigDecimal.class, description = "Any number of input numbers")
1336     *     private List&lt;BigDecimal&gt; files = new ArrayList&lt;BigDecimal&gt;();
1337     *
1338     *     &#064;Option(names = { "-h", "--help", "-?", "-help"}, help = true, description = "Display this help and exit")
1339     *     private boolean help;
1340     * }
1341     * </pre><p>
1342     * A field cannot be annotated with both {@code @Parameters} and {@code @Option} or a {@code ParameterException}
1343     * is thrown.</p>
1344     */
1345    @Retention(RetentionPolicy.RUNTIME)
1346    @Target(ElementType.FIELD)
1347    public @interface Parameters {
1348        /** Specify an index ("0", or "1", etc.) to pick which of the command line arguments should be assigned to this
1349         * field. For array or Collection fields, you can also specify an index range ("0..3", or "2..*", etc.) to assign
1350         * a subset of the command line arguments to this field. The default is "*", meaning all command line arguments.
1351         * @return an index or range specifying which of the command line arguments should be assigned to this field
1352         */
1353        String index() default "*";
1354
1355        /** Description of the parameter(s), used when generating the usage documentation.
1356         * @return the description of the parameter(s)
1357         */
1358        String[] description() default {};
1359
1360        /**
1361         * Specifies the minimum number of required parameters and the maximum number of accepted parameters. If a
1362         * positive arity is declared, and the user specifies an insufficient number of parameters on the command line,
1363         * {@link MissingParameterException} is thrown by the {@link #parse(String...)} method.
1364         * <p>The default depends on the type of the parameter: booleans require no parameters, arrays and Collections
1365         * accept zero to any number of parameters, and any other type accepts one parameter.</p>
1366         * @return the range of minimum and maximum parameters accepted by this command
1367         */
1368        String arity() default "";
1369
1370        /**
1371         * Specify a {@code paramLabel} for the parameter to be used in the usage help message. If omitted,
1372         * picocli uses the field name in fish brackets ({@code '<'} and {@code '>'}) by default. Example:
1373         * <pre>class Example {
1374         *     &#064;Parameters(paramLabel="FILE", description="path of the input FILE(s)")
1375         *     private File[] inputFiles;
1376         * }</pre>
1377         * <p>By default, the above gives a usage help message like the following:</p><pre>
1378         * Usage: &lt;main class&gt; [FILE...]
1379         * [FILE...]       path of the input FILE(s)
1380         * </pre>
1381         * @return name of the positional parameter used in the usage help message
1382         */
1383        String paramLabel() default "";
1384
1385        /**
1386         * <p>
1387         * Optionally specify a {@code type} to control exactly what Class the positional parameter should be converted
1388         * to. This may be useful when the field type is an interface or an abstract class. For example, a field can
1389         * be declared to have type {@code java.lang.Number}, and annotating {@code @Parameters(type=Short.class)}
1390         * ensures that the positional parameter value is converted to a {@code Short} before setting the field value.
1391         * </p><p>
1392         * For array fields whose <em>component</em> type is an interface or abstract class, specify the concrete <em>component</em> type.
1393         * For example, a field with type {@code Number[]} may be annotated with {@code @Parameters(type=Short.class)}
1394         * to ensure that positional parameter values are converted to {@code Short} before adding an element to the array.
1395         * </p><p>
1396         * Picocli will use the {@link ITypeConverter} that is
1397         * {@linkplain #registerConverter(Class, ITypeConverter) registered} for the specified type to convert
1398         * the raw String values before modifying the field value.
1399         * </p><p>
1400         * Prior to 2.0, the {@code type} attribute was necessary for {@code Collection} and {@code Map} fields,
1401         * but starting from 2.0 picocli will infer the component type from the generic type's type arguments.
1402         * For example, for a field of type {@code Map<TimeUnit, Long>} picocli will know the positional parameter
1403         * should be split up in key=value pairs, where the key should be converted to a {@code java.util.concurrent.TimeUnit}
1404         * enum value, and the value should be converted to a {@code Long}. No {@code @Parameters(type=...)} type attribute
1405         * is required for this. For generic types with wildcards, picocli will take the specified upper or lower bound
1406         * as the Class to convert to, unless the {@code @Parameters} annotation specifies an explicit {@code type} attribute.
1407         * </p><p>
1408         * If the field type is a raw collection or a raw map, and you want it to contain other values than Strings,
1409         * or if the generic type's type arguments are interfaces or abstract classes, you may
1410         * specify a {@code type} attribute to control the Class that the positional parameter should be converted to.
1411         * @return the type(s) to convert the raw String values
1412         */
1413        Class<?>[] type() default {};
1414
1415        /**
1416         * Specify a regular expression to use to split positional parameter values before applying them to the field.
1417         * All elements resulting from the split are added to the array or Collection. Ignored for single-value fields.
1418         * @return a regular expression to split operand values or {@code ""} if the value should not be split
1419         * @see String#split(String)
1420         */
1421        String split() default "";
1422
1423        /**
1424         * Set {@code hidden=true} if this parameter should not be included in the usage message.
1425         * @return whether this parameter should be excluded from the usage message
1426         */
1427        boolean hidden() default false;
1428    }
1429
1430    /**
1431     * <p>Annotate your class with {@code @Command} when you want more control over the format of the generated help
1432     * message.
1433     * </p><pre>
1434     * &#064;Command(name      = "Encrypt",
1435     *        description = "Encrypt FILE(s), or standard input, to standard output or to the output file.",
1436     *        footer      = "Copyright (c) 2017")
1437     * public class Encrypt {
1438     *     &#064;Parameters(paramLabel = "FILE", type = File.class, description = "Any number of input files")
1439     *     private List&lt;File&gt; files     = new ArrayList&lt;File&gt;();
1440     *
1441     *     &#064;Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
1442     *     private File outputFile;
1443     * }</pre>
1444     * <p>
1445     * The structure of a help message looks like this:
1446     * </p><ul>
1447     *   <li>[header]</li>
1448     *   <li>[synopsis]: {@code Usage: <commandName> [OPTIONS] [FILE...]}</li>
1449     *   <li>[description]</li>
1450     *   <li>[parameter list]: {@code      [FILE...]   Any number of input files}</li>
1451     *   <li>[option list]: {@code   -h, --help   prints this help message and exits}</li>
1452     *   <li>[footer]</li>
1453     * </ul> */
1454    @Retention(RetentionPolicy.RUNTIME)
1455    @Target({ElementType.TYPE, ElementType.LOCAL_VARIABLE, ElementType.PACKAGE})
1456    public @interface Command {
1457        /** Program name to show in the synopsis. If omitted, {@code "<main class>"} is used.
1458         * For {@linkplain #subcommands() declaratively added} subcommands, this attribute is also used
1459         * by the parser to recognize subcommands in the command line arguments.
1460         * @return the program name to show in the synopsis
1461         * @see Help#commandName */
1462        String name() default "<main class>";
1463
1464        /** A list of classes to instantiate and register as subcommands. When registering subcommands declaratively
1465         * like this, you don't need to call the {@link CommandLine#addSubcommand(String, Object)} method. For example, this:
1466         * <pre>
1467         * &#064;Command(subcommands = {
1468         *         GitStatus.class,
1469         *         GitCommit.class,
1470         *         GitBranch.class })
1471         * public class Git { ... }
1472         *
1473         * CommandLine commandLine = new CommandLine(new Git());
1474         * </pre> is equivalent to this:
1475         * <pre>
1476         * // alternative: programmatically add subcommands.
1477         * // NOTE: in this case there should be no `subcommands` attribute on the @Command annotation.
1478         * &#064;Command public class Git { ... }
1479         *
1480         * CommandLine commandLine = new CommandLine(new Git())
1481         *         .addSubcommand("status",   new GitStatus())
1482         *         .addSubcommand("commit",   new GitCommit())
1483         *         .addSubcommand("branch",   new GitBranch());
1484         * </pre>
1485         * @return the declaratively registered subcommands of this command, or an empty array if none
1486         * @see CommandLine#addSubcommand(String, Object)
1487         * @since 0.9.8
1488         */
1489        Class<?>[] subcommands() default {};
1490
1491        /** String that separates options from option parameters. Default is {@code "="}. Spaces are also accepted.
1492         * @return the string that separates options from option parameters, used both when parsing and when generating usage help
1493         * @see Help#separator
1494         * @see CommandLine#setSeparator(String) */
1495        String separator() default "=";
1496
1497        /** Version information for this command, to print to the console when the user specifies an
1498         * {@linkplain Option#versionHelp() option} to request version help. This is not part of the usage help message.
1499         *
1500         * @return a string or an array of strings with version information about this command.
1501         * @since 0.9.8
1502         * @see CommandLine#printVersionHelp(PrintStream)
1503         */
1504        String[] version() default {};
1505
1506        /** Set the heading preceding the header section. May contain embedded {@linkplain java.util.Formatter format specifiers}.
1507         * @return the heading preceding the header section
1508         * @see Help#headerHeading(Object...)  */
1509        String headerHeading() default "";
1510
1511        /** Optional summary description of the command, shown before the synopsis.
1512         * @return summary description of the command
1513         * @see Help#header
1514         * @see Help#header(Object...)  */
1515        String[] header() default {};
1516
1517        /** Set the heading preceding the synopsis text. May contain embedded
1518         * {@linkplain java.util.Formatter format specifiers}. The default heading is {@code "Usage: "} (without a line
1519         * break between the heading and the synopsis text).
1520         * @return the heading preceding the synopsis text
1521         * @see Help#synopsisHeading(Object...)  */
1522        String synopsisHeading() default "Usage: ";
1523
1524        /** Specify {@code true} to generate an abbreviated synopsis like {@code "<main> [OPTIONS] [PARAMETERS...]"}.
1525         * By default, a detailed synopsis with individual option names and parameters is generated.
1526         * @return whether the synopsis should be abbreviated
1527         * @see Help#abbreviateSynopsis
1528         * @see Help#abbreviatedSynopsis()
1529         * @see Help#detailedSynopsis(Comparator, boolean) */
1530        boolean abbreviateSynopsis() default false;
1531
1532        /** Specify one or more custom synopsis lines to display instead of an auto-generated synopsis.
1533         * @return custom synopsis text to replace the auto-generated synopsis
1534         * @see Help#customSynopsis
1535         * @see Help#customSynopsis(Object...) */
1536        String[] customSynopsis() default {};
1537
1538        /** Set the heading preceding the description section. May contain embedded {@linkplain java.util.Formatter format specifiers}.
1539         * @return the heading preceding the description section
1540         * @see Help#descriptionHeading(Object...)  */
1541        String descriptionHeading() default "";
1542
1543        /** Optional text to display between the synopsis line(s) and the list of options.
1544         * @return description of this command
1545         * @see Help#description
1546         * @see Help#description(Object...) */
1547        String[] description() default {};
1548
1549        /** Set the heading preceding the parameters list. May contain embedded {@linkplain java.util.Formatter format specifiers}.
1550         * @return the heading preceding the parameters list
1551         * @see Help#parameterListHeading(Object...)  */
1552        String parameterListHeading() default "";
1553
1554        /** Set the heading preceding the options list. May contain embedded {@linkplain java.util.Formatter format specifiers}.
1555         * @return the heading preceding the options list
1556         * @see Help#optionListHeading(Object...)  */
1557        String optionListHeading() default "";
1558
1559        /** Specify {@code false} to show Options in declaration order. The default is to sort alphabetically.
1560         * @return whether options should be shown in alphabetic order.
1561         * @see Help#sortOptions */
1562        boolean sortOptions() default true;
1563
1564        /** Prefix required options with this character in the options list. The default is no marker: the synopsis
1565         * indicates which options and parameters are required.
1566         * @return the character to show in the options list to mark required options
1567         * @see Help#requiredOptionMarker */
1568        char requiredOptionMarker() default ' ';
1569
1570        /** Specify {@code true} to show default values in the description column of the options list (except for
1571         * boolean options). False by default.
1572         * @return whether the default values for options and parameters should be shown in the description column
1573         * @see Help#showDefaultValues */
1574        boolean showDefaultValues() default false;
1575
1576        /** Set the heading preceding the subcommands list. May contain embedded {@linkplain java.util.Formatter format specifiers}.
1577         * The default heading is {@code "Commands:%n"} (with a line break at the end).
1578         * @return the heading preceding the subcommands list
1579         * @see Help#commandListHeading(Object...)  */
1580        String commandListHeading() default "Commands:%n";
1581
1582        /** Set the heading preceding the footer section. May contain embedded {@linkplain java.util.Formatter format specifiers}.
1583         * @return the heading preceding the footer section
1584         * @see Help#footerHeading(Object...)  */
1585        String footerHeading() default "";
1586
1587        /** Optional text to display after the list of options.
1588         * @return text to display after the list of options
1589         * @see Help#footer
1590         * @see Help#footer(Object...) */
1591        String[] footer() default {};
1592    }
1593    /**
1594     * <p>
1595     * When parsing command line arguments and initializing
1596     * fields annotated with {@link Option @Option} or {@link Parameters @Parameters},
1597     * String values can be converted to any type for which a {@code ITypeConverter} is registered.
1598     * </p><p>
1599     * This interface defines the contract for classes that know how to convert a String into some domain object.
1600     * Custom converters can be registered with the {@link #registerConverter(Class, ITypeConverter)} method.
1601     * </p><p>
1602     * Java 8 lambdas make it easy to register custom type converters:
1603     * </p>
1604     * <pre>
1605     * commandLine.registerConverter(java.nio.file.Path.class, s -&gt; java.nio.file.Paths.get(s));
1606     * commandLine.registerConverter(java.time.Duration.class, s -&gt; java.time.Duration.parse(s));</pre>
1607     * <p>
1608     * Built-in type converters are pre-registered for the following java 1.5 types:
1609     * </p>
1610     * <ul>
1611     *   <li>all primitive types</li>
1612     *   <li>all primitive wrapper types: Boolean, Byte, Character, Double, Float, Integer, Long, Short</li>
1613     *   <li>any enum</li>
1614     *   <li>java.io.File</li>
1615     *   <li>java.math.BigDecimal</li>
1616     *   <li>java.math.BigInteger</li>
1617     *   <li>java.net.InetAddress</li>
1618     *   <li>java.net.URI</li>
1619     *   <li>java.net.URL</li>
1620     *   <li>java.nio.charset.Charset</li>
1621     *   <li>java.sql.Time</li>
1622     *   <li>java.util.Date</li>
1623     *   <li>java.util.UUID</li>
1624     *   <li>java.util.regex.Pattern</li>
1625     *   <li>StringBuilder</li>
1626     *   <li>CharSequence</li>
1627     *   <li>String</li>
1628     * </ul>
1629     * @param <K> the type of the object that is the result of the conversion
1630     */
1631    public interface ITypeConverter<K> {
1632        /**
1633         * Converts the specified command line argument value to some domain object.
1634         * @param value the command line argument String value
1635         * @return the resulting domain object
1636         * @throws Exception an exception detailing what went wrong during the conversion
1637         */
1638        K convert(String value) throws Exception;
1639    }
1640    /** Describes the number of parameters required and accepted by an option or a positional parameter.
1641     * @since 0.9.7
1642     */
1643    public static class Range implements Comparable<Range> {
1644        /** Required number of parameters for an option or positional parameter. */
1645        public final int min;
1646        /** Maximum accepted number of parameters for an option or positional parameter. */
1647        public final int max;
1648        public final boolean isVariable;
1649        private final boolean isUnspecified;
1650        private final String originalValue;
1651
1652        /** Constructs a new Range object with the specified parameters.
1653         * @param min minimum number of required parameters
1654         * @param max maximum number of allowed parameters (or Integer.MAX_VALUE if variable)
1655         * @param variable {@code true} if any number or parameters is allowed, {@code false} otherwise
1656         * @param unspecified {@code true} if no arity was specified on the option/parameter (value is based on type)
1657         * @param originalValue the original value that was specified on the option or parameter
1658         */
1659        public Range(final int min, final int max, final boolean variable, final boolean unspecified, final String originalValue) {
1660            this.min = min;
1661            this.max = max;
1662            this.isVariable = variable;
1663            this.isUnspecified = unspecified;
1664            this.originalValue = originalValue;
1665        }
1666        /** Returns a new {@code Range} based on the {@link Option#arity()} annotation on the specified field,
1667         * or the field type's default arity if no arity was specified.
1668         * @param field the field whose Option annotation to inspect
1669         * @return a new {@code Range} based on the Option arity annotation on the specified field */
1670        public static Range optionArity(final Field field) {
1671            return field.isAnnotationPresent(Option.class)
1672                    ? adjustForType(Range.valueOf(field.getAnnotation(Option.class).arity()), field)
1673                    : new Range(0, 0, false, true, "0");
1674        }
1675        /** Returns a new {@code Range} based on the {@link Parameters#arity()} annotation on the specified field,
1676         * or the field type's default arity if no arity was specified.
1677         * @param field the field whose Parameters annotation to inspect
1678         * @return a new {@code Range} based on the Parameters arity annotation on the specified field */
1679        public static Range parameterArity(final Field field) {
1680            return field.isAnnotationPresent(Parameters.class)
1681                    ? adjustForType(Range.valueOf(field.getAnnotation(Parameters.class).arity()), field)
1682                    : new Range(0, 0, false, true, "0");
1683        }
1684        /** Returns a new {@code Range} based on the {@link Parameters#index()} annotation on the specified field.
1685         * @param field the field whose Parameters annotation to inspect
1686         * @return a new {@code Range} based on the Parameters index annotation on the specified field */
1687        public static Range parameterIndex(final Field field) {
1688            return field.isAnnotationPresent(Parameters.class)
1689                    ? Range.valueOf(field.getAnnotation(Parameters.class).index())
1690                    : new Range(0, 0, false, true, "0");
1691        }
1692        static Range adjustForType(final Range result, final Field field) {
1693            return result.isUnspecified ? defaultArity(field) : result;
1694        }
1695        /** Returns the default arity {@code Range}: for {@link Option options} this is 0 for booleans and 1 for
1696         * other types, for {@link Parameters parameters} booleans have arity 0, arrays or Collections have
1697         * arity "0..*", and other types have arity 1.
1698         * @param field the field whose default arity to return
1699         * @return a new {@code Range} indicating the default arity of the specified field
1700         * @since 2.0 */
1701        public static Range defaultArity(final Field field) {
1702            final Class<?> type = field.getType();
1703            if (field.isAnnotationPresent(Option.class)) {
1704                return defaultArity(type);
1705            }
1706            if (isMultiValue(type)) {
1707                return Range.valueOf("0..1");
1708            }
1709            return Range.valueOf("1");// for single-valued fields (incl. boolean positional parameters)
1710        }
1711        /** Returns the default arity {@code Range} for {@link Option options}: booleans have arity 0, other types have arity 1.
1712         * @param type the type whose default arity to return
1713         * @return a new {@code Range} indicating the default arity of the specified type */
1714        public static Range defaultArity(final Class<?> type) {
1715            return isBoolean(type) ? Range.valueOf("0") : Range.valueOf("1");
1716        }
1717        private int size() { return 1 + max - min; }
1718        static Range parameterCapacity(final Field field) {
1719            final Range arity = parameterArity(field);
1720            if (!isMultiValue(field)) { return arity; }
1721            final Range index = parameterIndex(field);
1722            if (arity.max == 0)    { return arity; }
1723            if (index.size() == 1) { return arity; }
1724            if (index.isVariable)  { return Range.valueOf(arity.min + "..*"); }
1725            if (arity.size() == 1) { return Range.valueOf(arity.min * index.size() + ""); }
1726            if (arity.isVariable)  { return Range.valueOf(arity.min * index.size() + "..*"); }
1727            return Range.valueOf(arity.min * index.size() + ".." + arity.max * index.size());
1728        }
1729        /** Leniently parses the specified String as an {@code Range} value and return the result. A range string can
1730         * be a fixed integer value or a range of the form {@code MIN_VALUE + ".." + MAX_VALUE}. If the
1731         * {@code MIN_VALUE} string is not numeric, the minimum is zero. If the {@code MAX_VALUE} is not numeric, the
1732         * range is taken to be variable and the maximum is {@code Integer.MAX_VALUE}.
1733         * @param range the value range string to parse
1734         * @return a new {@code Range} value */
1735        public static Range valueOf(String range) {
1736            range = range.trim();
1737            final boolean unspecified = range.length() == 0 || range.startsWith(".."); // || range.endsWith("..");
1738            int min = -1, max = -1;
1739            boolean variable = false;
1740            int dots = -1;
1741            if ((dots = range.indexOf("..")) >= 0) {
1742                min = parseInt(range.substring(0, dots), 0);
1743                max = parseInt(range.substring(dots + 2), Integer.MAX_VALUE);
1744                variable = max == Integer.MAX_VALUE;
1745            } else {
1746                max = parseInt(range, Integer.MAX_VALUE);
1747                variable = max == Integer.MAX_VALUE;
1748                min = variable ? 0 : max;
1749            }
1750            final Range result = new Range(min, max, variable, unspecified, range);
1751            return result;
1752        }
1753        private static int parseInt(final String str, final int defaultValue) {
1754            try {
1755                return Integer.parseInt(str);
1756            } catch (final Exception ex) {
1757                return defaultValue;
1758            }
1759        }
1760        /** Returns a new Range object with the {@code min} value replaced by the specified value.
1761         * The {@code max} of the returned Range is guaranteed not to be less than the new {@code min} value.
1762         * @param newMin the {@code min} value of the returned Range object
1763         * @return a new Range object with the specified {@code min} value */
1764        public Range min(final int newMin) { return new Range(newMin, Math.max(newMin, max), isVariable, isUnspecified, originalValue); }
1765
1766        /** Returns a new Range object with the {@code max} value replaced by the specified value.
1767         * The {@code min} of the returned Range is guaranteed not to be greater than the new {@code max} value.
1768         * @param newMax the {@code max} value of the returned Range object
1769         * @return a new Range object with the specified {@code max} value */
1770        public Range max(final int newMax) { return new Range(Math.min(min, newMax), newMax, isVariable, isUnspecified, originalValue); }
1771
1772        /**
1773         * Returns {@code true} if this Range includes the specified value, {@code false} otherwise.
1774         * @param value the value to check
1775         * @return {@code true} if the specified value is not less than the minimum and not greater than the maximum of this Range
1776         */
1777        public boolean contains(final int value) { return min <= value && max >= value; }
1778
1779        @Override
1780        public boolean equals(final Object object) {
1781            if (!(object instanceof Range)) { return false; }
1782            final Range other = (Range) object;
1783            return other.max == this.max && other.min == this.min && other.isVariable == this.isVariable;
1784        }
1785        @Override
1786        public int hashCode() {
1787            return ((17 * 37 + max) * 37 + min) * 37 + (isVariable ? 1 : 0);
1788        }
1789        @Override
1790        public String toString() {
1791            return min == max ? String.valueOf(min) : min + ".." + (isVariable ? "*" : max);
1792        }
1793        @Override
1794        public int compareTo(final Range other) {
1795            final int result = min - other.min;
1796            return (result == 0) ? max - other.max : result;
1797        }
1798    }
1799    static void init(final Class<?> cls,
1800                              final List<Field> requiredFields,
1801                              final Map<String, Field> optionName2Field,
1802                              final Map<Character, Field> singleCharOption2Field,
1803                              final List<Field> positionalParametersFields) {
1804        final Field[] declaredFields = cls.getDeclaredFields();
1805        for (final Field field : declaredFields) {
1806            field.setAccessible(true);
1807            if (field.isAnnotationPresent(Option.class)) {
1808                final Option option = field.getAnnotation(Option.class);
1809                if (option.required()) {
1810                    requiredFields.add(field);
1811                }
1812                for (final String name : option.names()) { // cannot be null or empty
1813                    final Field existing = optionName2Field.put(name, field);
1814                    if (existing != null && existing != field) {
1815                        throw DuplicateOptionAnnotationsException.create(name, field, existing);
1816                    }
1817                    if (name.length() == 2 && name.startsWith("-")) {
1818                        final char flag = name.charAt(1);
1819                        final Field existing2 = singleCharOption2Field.put(flag, field);
1820                        if (existing2 != null && existing2 != field) {
1821                            throw DuplicateOptionAnnotationsException.create(name, field, existing2);
1822                        }
1823                    }
1824                }
1825            }
1826            if (field.isAnnotationPresent(Parameters.class)) {
1827                if (field.isAnnotationPresent(Option.class)) {
1828                    throw new DuplicateOptionAnnotationsException("A field can be either @Option or @Parameters, but '"
1829                            + field.getName() + "' is both.");
1830                }
1831                positionalParametersFields.add(field);
1832                final Range arity = Range.parameterArity(field);
1833                if (arity.min > 0) {
1834                    requiredFields.add(field);
1835                }
1836            }
1837        }
1838    }
1839    static void validatePositionalParameters(final List<Field> positionalParametersFields) {
1840        int min = 0;
1841        for (final Field field : positionalParametersFields) {
1842            final Range index = Range.parameterIndex(field);
1843            if (index.min > min) {
1844                throw new ParameterIndexGapException("Missing field annotated with @Parameter(index=" + min +
1845                        "). Nearest field '" + field.getName() + "' has index=" + index.min);
1846            }
1847            min = Math.max(min, index.max);
1848            min = min == Integer.MAX_VALUE ? min : min + 1;
1849        }
1850    }
1851    private static <T> Stack<T> reverse(final Stack<T> stack) {
1852        Collections.reverse(stack);
1853        return stack;
1854    }
1855    /**
1856     * Helper class responsible for processing command line arguments.
1857     */
1858    private class Interpreter {
1859        private final Map<String, CommandLine> commands                  = new LinkedHashMap<>();
1860        private final Map<Class<?>, ITypeConverter<?>> converterRegistry = new HashMap<>();
1861        private final Map<String, Field> optionName2Field                = new HashMap<>();
1862        private final Map<Character, Field> singleCharOption2Field       = new HashMap<>();
1863        private final List<Field> requiredFields                         = new ArrayList<>();
1864        private final List<Field> positionalParametersFields             = new ArrayList<>();
1865        private final Object command;
1866        private boolean isHelpRequested;
1867        private String separator = Help.DEFAULT_SEPARATOR;
1868        private int position;
1869
1870        Interpreter(final Object command) {
1871            converterRegistry.put(Path.class,          new BuiltIn.PathConverter());
1872            converterRegistry.put(Object.class,        new BuiltIn.StringConverter());
1873            converterRegistry.put(String.class,        new BuiltIn.StringConverter());
1874            converterRegistry.put(StringBuilder.class, new BuiltIn.StringBuilderConverter());
1875            converterRegistry.put(CharSequence.class,  new BuiltIn.CharSequenceConverter());
1876            converterRegistry.put(Byte.class,          new BuiltIn.ByteConverter());
1877            converterRegistry.put(Byte.TYPE,           new BuiltIn.ByteConverter());
1878            converterRegistry.put(Boolean.class,       new BuiltIn.BooleanConverter());
1879            converterRegistry.put(Boolean.TYPE,        new BuiltIn.BooleanConverter());
1880            converterRegistry.put(Character.class,     new BuiltIn.CharacterConverter());
1881            converterRegistry.put(Character.TYPE,      new BuiltIn.CharacterConverter());
1882            converterRegistry.put(Short.class,         new BuiltIn.ShortConverter());
1883            converterRegistry.put(Short.TYPE,          new BuiltIn.ShortConverter());
1884            converterRegistry.put(Integer.class,       new BuiltIn.IntegerConverter());
1885            converterRegistry.put(Integer.TYPE,        new BuiltIn.IntegerConverter());
1886            converterRegistry.put(Long.class,          new BuiltIn.LongConverter());
1887            converterRegistry.put(Long.TYPE,           new BuiltIn.LongConverter());
1888            converterRegistry.put(Float.class,         new BuiltIn.FloatConverter());
1889            converterRegistry.put(Float.TYPE,          new BuiltIn.FloatConverter());
1890            converterRegistry.put(Double.class,        new BuiltIn.DoubleConverter());
1891            converterRegistry.put(Double.TYPE,         new BuiltIn.DoubleConverter());
1892            converterRegistry.put(File.class,          new BuiltIn.FileConverter());
1893            converterRegistry.put(URI.class,           new BuiltIn.URIConverter());
1894            converterRegistry.put(URL.class,           new BuiltIn.URLConverter());
1895            converterRegistry.put(Date.class,          new BuiltIn.ISO8601DateConverter());
1896            converterRegistry.put(Time.class,          new BuiltIn.ISO8601TimeConverter());
1897            converterRegistry.put(BigDecimal.class,    new BuiltIn.BigDecimalConverter());
1898            converterRegistry.put(BigInteger.class,    new BuiltIn.BigIntegerConverter());
1899            converterRegistry.put(Charset.class,       new BuiltIn.CharsetConverter());
1900            converterRegistry.put(InetAddress.class,   new BuiltIn.InetAddressConverter());
1901            converterRegistry.put(Pattern.class,       new BuiltIn.PatternConverter());
1902            converterRegistry.put(UUID.class,          new BuiltIn.UUIDConverter());
1903
1904            this.command                 = Assert.notNull(command, "command");
1905            Class<?> cls                 = command.getClass();
1906            String declaredName          = null;
1907            String declaredSeparator     = null;
1908            boolean hasCommandAnnotation = false;
1909            while (cls != null) {
1910                init(cls, requiredFields, optionName2Field, singleCharOption2Field, positionalParametersFields);
1911                if (cls.isAnnotationPresent(Command.class)) {
1912                    hasCommandAnnotation = true;
1913                    final Command cmd = cls.getAnnotation(Command.class);
1914                    declaredSeparator = (declaredSeparator == null) ? cmd.separator() : declaredSeparator;
1915                    declaredName = (declaredName == null) ? cmd.name() : declaredName;
1916                    CommandLine.this.versionLines.addAll(Arrays.asList(cmd.version()));
1917
1918                    for (final Class<?> sub : cmd.subcommands()) {
1919                        final Command subCommand = sub.getAnnotation(Command.class);
1920                        if (subCommand == null || Help.DEFAULT_COMMAND_NAME.equals(subCommand.name())) {
1921                            throw new InitializationException("Subcommand " + sub.getName() +
1922                                    " is missing the mandatory @Command annotation with a 'name' attribute");
1923                        }
1924                        try {
1925                            final Constructor<?> constructor = sub.getDeclaredConstructor();
1926                            constructor.setAccessible(true);
1927                            final CommandLine commandLine = toCommandLine(constructor.newInstance());
1928                            commandLine.parent = CommandLine.this;
1929                            commands.put(subCommand.name(), commandLine);
1930                        }
1931                        catch (final InitializationException ex) { throw ex; }
1932                        catch (final NoSuchMethodException ex) { throw new InitializationException("Cannot instantiate subcommand " +
1933                                sub.getName() + ": the class has no constructor", ex); }
1934                        catch (final Exception ex) {
1935                            throw new InitializationException("Could not instantiate and add subcommand " +
1936                                    sub.getName() + ": " + ex, ex);
1937                        }
1938                    }
1939                }
1940                cls = cls.getSuperclass();
1941            }
1942            separator = declaredSeparator != null ? declaredSeparator : separator;
1943            CommandLine.this.commandName = declaredName != null ? declaredName : CommandLine.this.commandName;
1944            Collections.sort(positionalParametersFields, new PositionalParametersSorter());
1945            validatePositionalParameters(positionalParametersFields);
1946
1947            if (positionalParametersFields.isEmpty() && optionName2Field.isEmpty() && !hasCommandAnnotation) {
1948                throw new InitializationException(command + " (" + command.getClass() +
1949                        ") is not a command: it has no @Command, @Option or @Parameters annotations");
1950            }
1951        }
1952
1953        /**
1954         * Entry point into parsing command line arguments.
1955         * @param args the command line arguments
1956         * @return a list with all commands and subcommands initialized by this method
1957         * @throws ParameterException if the specified command line arguments are invalid
1958         */
1959        List<CommandLine> parse(final String... args) {
1960            Assert.notNull(args, "argument array");
1961            if (tracer.isInfo()) {tracer.info("Parsing %d command line args %s%n", args.length, Arrays.toString(args));}
1962            final Stack<String> arguments = new Stack<>();
1963            for (int i = args.length - 1; i >= 0; i--) {
1964                arguments.push(args[i]);
1965            }
1966            final List<CommandLine> result = new ArrayList<>();
1967            parse(result, arguments, args);
1968            return result;
1969        }
1970
1971        private void parse(final List<CommandLine> parsedCommands, final Stack<String> argumentStack, final String[] originalArgs) {
1972            // first reset any state in case this CommandLine instance is being reused
1973            isHelpRequested = false;
1974            CommandLine.this.versionHelpRequested = false;
1975            CommandLine.this.usageHelpRequested = false;
1976
1977            final Class<?> cmdClass = this.command.getClass();
1978            if (tracer.isDebug()) {tracer.debug("Initializing %s: %d options, %d positional parameters, %d required, %d subcommands.%n", cmdClass.getName(), new HashSet<>(optionName2Field.values()).size(), positionalParametersFields.size(), requiredFields.size(), commands.size());}
1979            parsedCommands.add(CommandLine.this);
1980            final List<Field> required = new ArrayList<>(requiredFields);
1981            final Set<Field> initialized = new HashSet<>();
1982            Collections.sort(required, new PositionalParametersSorter());
1983            try {
1984                processArguments(parsedCommands, argumentStack, required, initialized, originalArgs);
1985            } catch (final ParameterException ex) {
1986                throw ex;
1987            } catch (final Exception ex) {
1988                final int offendingArgIndex = originalArgs.length - argumentStack.size() - 1;
1989                final String arg = offendingArgIndex >= 0 && offendingArgIndex < originalArgs.length ? originalArgs[offendingArgIndex] : "?";
1990                throw ParameterException.create(CommandLine.this, ex, arg, offendingArgIndex, originalArgs);
1991            }
1992            if (!isAnyHelpRequested() && !required.isEmpty()) {
1993                for (final Field missing : required) {
1994                    if (missing.isAnnotationPresent(Option.class)) {
1995                        throw MissingParameterException.create(CommandLine.this, required, separator);
1996                    } else {
1997                        assertNoMissingParameters(missing, Range.parameterArity(missing).min, argumentStack);
1998                    }
1999                }
2000            }
2001            if (!unmatchedArguments.isEmpty()) {
2002                if (!isUnmatchedArgumentsAllowed()) { throw new UnmatchedArgumentException(CommandLine.this, unmatchedArguments); }
2003                if (tracer.isWarn()) { tracer.warn("Unmatched arguments: %s%n", unmatchedArguments); }
2004            }
2005        }
2006
2007        private void processArguments(final List<CommandLine> parsedCommands,
2008                                      final Stack<String> args,
2009                                      final Collection<Field> required,
2010                                      final Set<Field> initialized,
2011                                      final String[] originalArgs) throws Exception {
2012            // arg must be one of:
2013            // 1. the "--" double dash separating options from positional arguments
2014            // 1. a stand-alone flag, like "-v" or "--verbose": no value required, must map to boolean or Boolean field
2015            // 2. a short option followed by an argument, like "-f file" or "-ffile": may map to any type of field
2016            // 3. a long option followed by an argument, like "-file out.txt" or "-file=out.txt"
2017            // 3. one or more remaining arguments without any associated options. Must be the last in the list.
2018            // 4. a combination of stand-alone options, like "-vxr". Equivalent to "-v -x -r", "-v true -x true -r true"
2019            // 5. a combination of stand-alone options and one option with an argument, like "-vxrffile"
2020
2021            while (!args.isEmpty()) {
2022                String arg = args.pop();
2023                if (tracer.isDebug()) {tracer.debug("Processing argument '%s'. Remainder=%s%n", arg, reverse((Stack<String>) args.clone()));}
2024
2025                // Double-dash separates options from positional arguments.
2026                // If found, then interpret the remaining args as positional parameters.
2027                if ("--".equals(arg)) {
2028                    tracer.info("Found end-of-options delimiter '--'. Treating remainder as positional parameters.%n");
2029                    processRemainderAsPositionalParameters(required, initialized, args);
2030                    return; // we are done
2031                }
2032
2033                // if we find another command, we are done with the current command
2034                if (commands.containsKey(arg)) {
2035                    if (!isHelpRequested && !required.isEmpty()) { // ensure current command portion is valid
2036                        throw MissingParameterException.create(CommandLine.this, required, separator);
2037                    }
2038                    if (tracer.isDebug()) {tracer.debug("Found subcommand '%s' (%s)%n", arg, commands.get(arg).interpreter.command.getClass().getName());}
2039                    commands.get(arg).interpreter.parse(parsedCommands, args, originalArgs);
2040                    return; // remainder done by the command
2041                }
2042
2043                // First try to interpret the argument as a single option (as opposed to a compact group of options).
2044                // A single option may be without option parameters, like "-v" or "--verbose" (a boolean value),
2045                // or an option may have one or more option parameters.
2046                // A parameter may be attached to the option.
2047                boolean paramAttachedToOption = false;
2048                final int separatorIndex = arg.indexOf(separator);
2049                if (separatorIndex > 0) {
2050                    final String key = arg.substring(0, separatorIndex);
2051                    // be greedy. Consume the whole arg as an option if possible.
2052                    if (optionName2Field.containsKey(key) && !optionName2Field.containsKey(arg)) {
2053                        paramAttachedToOption = true;
2054                        final String optionParam = arg.substring(separatorIndex + separator.length());
2055                        args.push(optionParam);
2056                        arg = key;
2057                        if (tracer.isDebug()) {tracer.debug("Separated '%s' option from '%s' option parameter%n", key, optionParam);}
2058                    } else if (tracer.isDebug()) {tracer.debug("'%s' contains separator '%s' but '%s' is not a known option%n", arg, separator, key);}
2059                } else if (tracer.isDebug()) {tracer.debug("'%s' cannot be separated into <option>%s<option-parameter>%n", arg, separator);}
2060                if (optionName2Field.containsKey(arg)) {
2061                    processStandaloneOption(required, initialized, arg, args, paramAttachedToOption);
2062                }
2063                // Compact (single-letter) options can be grouped with other options or with an argument.
2064                // only single-letter options can be combined with other options or with an argument
2065                else if (arg.length() > 2 && arg.startsWith("-")) {
2066                    if (tracer.isDebug()) {tracer.debug("Trying to process '%s' as clustered short options%n", arg, args);}
2067                    processClusteredShortOptions(required, initialized, arg, args);
2068                }
2069                // The argument could not be interpreted as an option.
2070                // We take this to mean that the remainder are positional arguments
2071                else {
2072                    args.push(arg);
2073                    if (tracer.isDebug()) {tracer.debug("Could not find option '%s', deciding whether to treat as unmatched option or positional parameter...%n", arg);}
2074                    if (resemblesOption(arg)) { handleUnmatchedArguments(args.pop()); continue; } // #149
2075                    if (tracer.isDebug()) {tracer.debug("No option named '%s' found. Processing remainder as positional parameters%n", arg);}
2076                    processPositionalParameter(required, initialized, args);
2077                }
2078            }
2079        }
2080        private boolean resemblesOption(final String arg) {
2081            int count = 0;
2082            for (final String optionName : optionName2Field.keySet()) {
2083                for (int i = 0; i < arg.length(); i++) {
2084                    if (optionName.length() > i && arg.charAt(i) == optionName.charAt(i)) { count++; } else { break; }
2085                }
2086            }
2087            final boolean result = count > 0 && count * 10 >= optionName2Field.size() * 9; // at least one prefix char in common with 9 out of 10 options
2088            if (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, optionName2Field.size());}
2089            return result;
2090        }
2091        private void handleUnmatchedArguments(final String arg) {final Stack<String> args = new Stack<>(); args.add(arg); handleUnmatchedArguments(args);}
2092        private void handleUnmatchedArguments(final Stack<String> args) {
2093            while (!args.isEmpty()) { unmatchedArguments.add(args.pop()); } // addAll would give args in reverse order
2094        }
2095
2096        private void processRemainderAsPositionalParameters(final Collection<Field> required, final Set<Field> initialized, final Stack<String> args) throws Exception {
2097            while (!args.empty()) {
2098                processPositionalParameter(required, initialized, args);
2099            }
2100        }
2101        private void processPositionalParameter(final Collection<Field> required, final Set<Field> initialized, final Stack<String> args) throws Exception {
2102            if (tracer.isDebug()) {tracer.debug("Processing next arg as a positional parameter at index=%d. Remainder=%s%n", position, reverse((Stack<String>) args.clone()));}
2103            int consumed = 0;
2104            for (final Field positionalParam : positionalParametersFields) {
2105                final Range indexRange = Range.parameterIndex(positionalParam);
2106                if (!indexRange.contains(position)) {
2107                    continue;
2108                }
2109                @SuppressWarnings("unchecked")
2110                final
2111                Stack<String> argsCopy = (Stack<String>) args.clone();
2112                final Range arity = Range.parameterArity(positionalParam);
2113                if (tracer.isDebug()) {tracer.debug("Position %d is in index range %s. Trying to assign args to %s, arity=%s%n", position, indexRange, positionalParam, arity);}
2114                assertNoMissingParameters(positionalParam, arity.min, argsCopy);
2115                final int originalSize = argsCopy.size();
2116                applyOption(positionalParam, Parameters.class, arity, false, argsCopy, initialized, "args[" + indexRange + "] at position " + position);
2117                final int count = originalSize - argsCopy.size();
2118                if (count > 0) { required.remove(positionalParam); }
2119                consumed = Math.max(consumed, count);
2120            }
2121            // remove processed args from the stack
2122            for (int i = 0; i < consumed; i++) { args.pop(); }
2123            position += consumed;
2124            if (tracer.isDebug()) {tracer.debug("Consumed %d arguments, moving position to index %d.%n", consumed, position);}
2125            if (consumed == 0 && !args.isEmpty()) {
2126                handleUnmatchedArguments(args.pop());
2127            }
2128        }
2129
2130        private void processStandaloneOption(final Collection<Field> required,
2131                                             final Set<Field> initialized,
2132                                             final String arg,
2133                                             final Stack<String> args,
2134                                             final boolean paramAttachedToKey) throws Exception {
2135            final Field field = optionName2Field.get(arg);
2136            required.remove(field);
2137            Range arity = Range.optionArity(field);
2138            if (paramAttachedToKey) {
2139                arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1
2140            }
2141            if (tracer.isDebug()) {tracer.debug("Found option named '%s': field %s, arity=%s%n", arg, field, arity);}
2142            applyOption(field, Option.class, arity, paramAttachedToKey, args, initialized, "option " + arg);
2143        }
2144
2145        private void processClusteredShortOptions(final Collection<Field> required,
2146                                                  final Set<Field> initialized,
2147                                                  final String arg,
2148                                                  final Stack<String> args)
2149                throws Exception {
2150            final String prefix = arg.substring(0, 1);
2151            String cluster = arg.substring(1);
2152            boolean paramAttachedToOption = true;
2153            do {
2154                if (cluster.length() > 0 && singleCharOption2Field.containsKey(cluster.charAt(0))) {
2155                    final Field field = singleCharOption2Field.get(cluster.charAt(0));
2156                    Range arity = Range.optionArity(field);
2157                    final String argDescription = "option " + prefix + cluster.charAt(0);
2158                    if (tracer.isDebug()) {tracer.debug("Found option '%s%s' in %s: field %s, arity=%s%n", prefix, cluster.charAt(0), arg, field, arity);}
2159                    required.remove(field);
2160                    cluster = cluster.length() > 0 ? cluster.substring(1) : "";
2161                    paramAttachedToOption = cluster.length() > 0;
2162                    if (cluster.startsWith(separator)) {// attached with separator, like -f=FILE or -v=true
2163                        cluster = cluster.substring(separator.length());
2164                        arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1
2165                    }
2166                    if (arity.min > 0 && !empty(cluster)) {
2167                        if (tracer.isDebug()) {tracer.debug("Trying to process '%s' as option parameter%n", cluster);}
2168                    }
2169                    // arity may be >= 1, or
2170                    // arity <= 0 && !cluster.startsWith(separator)
2171                    // e.g., boolean @Option("-v", arity=0, varargs=true); arg "-rvTRUE", remainder cluster="TRUE"
2172                    if (!empty(cluster)) {
2173                        args.push(cluster); // interpret remainder as option parameter
2174                    }
2175                    final int consumed = applyOption(field, Option.class, arity, paramAttachedToOption, args, initialized, argDescription);
2176                    // only return if cluster (and maybe more) was consumed, otherwise continue do-while loop
2177                    if (empty(cluster) || consumed > 0 || args.isEmpty()) {
2178                        return;
2179                    }
2180                    cluster = args.pop();
2181                } else { // cluster is empty || cluster.charAt(0) is not a short option key
2182                    if (cluster.length() == 0) { // we finished parsing a group of short options like -rxv
2183                        return; // return normally and parse the next arg
2184                    }
2185                    // We get here when the remainder of the cluster group is neither an option,
2186                    // nor a parameter that the last option could consume.
2187                    if (arg.endsWith(cluster)) {
2188                        args.push(paramAttachedToOption ? prefix + cluster : cluster);
2189                        if (args.peek().equals(arg)) { // #149 be consistent between unmatched short and long options
2190                            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);}
2191                            if (resemblesOption(arg)) { handleUnmatchedArguments(args.pop()); return; } // #149
2192                            processPositionalParameter(required, initialized, args);
2193                            return;
2194                        }
2195                        // remainder was part of a clustered group that could not be completely parsed
2196                        if (tracer.isDebug()) {tracer.debug("No option found for %s in %s%n", cluster, arg);}
2197                        handleUnmatchedArguments(args.pop());
2198                    } else {
2199                        args.push(cluster);
2200                        if (tracer.isDebug()) {tracer.debug("%s is not an option parameter for %s%n", cluster, arg);}
2201                        processPositionalParameter(required, initialized, args);
2202                    }
2203                    return;
2204                }
2205            } while (true);
2206        }
2207
2208        private int applyOption(final Field field,
2209                                final Class<?> annotation,
2210                                final Range arity,
2211                                final boolean valueAttachedToOption,
2212                                final Stack<String> args,
2213                                final Set<Field> initialized,
2214                                final String argDescription) throws Exception {
2215            updateHelpRequested(field);
2216            final int length = args.size();
2217            assertNoMissingParameters(field, arity.min, args);
2218
2219            Class<?> cls = field.getType();
2220            if (cls.isArray()) {
2221                return applyValuesToArrayField(field, annotation, arity, args, cls, argDescription);
2222            }
2223            if (Collection.class.isAssignableFrom(cls)) {
2224                return applyValuesToCollectionField(field, annotation, arity, args, cls, argDescription);
2225            }
2226            if (Map.class.isAssignableFrom(cls)) {
2227                return applyValuesToMapField(field, annotation, arity, args, cls, argDescription);
2228            }
2229            cls = getTypeAttribute(field)[0]; // field may be interface/abstract type, use annotation to get concrete type
2230            return applyValueToSingleValuedField(field, arity, args, cls, initialized, argDescription);
2231        }
2232
2233        private int applyValueToSingleValuedField(final Field field,
2234                                                  final Range arity,
2235                                                  final Stack<String> args,
2236                                                  final Class<?> cls,
2237                                                  final Set<Field> initialized,
2238                                                  final String argDescription) throws Exception {
2239            final boolean noMoreValues = args.isEmpty();
2240            String value = args.isEmpty() ? null : trim(args.pop()); // unquote the value
2241            int result = arity.min; // the number or args we need to consume
2242
2243            // special logic for booleans: BooleanConverter accepts only "true" or "false".
2244            if ((cls == Boolean.class || cls == Boolean.TYPE) && arity.min <= 0) {
2245
2246                // boolean option with arity = 0..1 or 0..*: value MAY be a param
2247                if (arity.max > 0 && ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value))) {
2248                    result = 1;            // if it is a varargs we only consume 1 argument if it is a boolean value
2249                } else {
2250                    if (value != null) {
2251                        args.push(value); // we don't consume the value
2252                    }
2253                    final Boolean currentValue = (Boolean) field.get(command);
2254                    value = String.valueOf(currentValue == null ? true : !currentValue); // #147 toggle existing boolean value
2255                }
2256            }
2257            if (noMoreValues && value == null) {
2258                return 0;
2259            }
2260            final ITypeConverter<?> converter = getTypeConverter(cls, field);
2261            final Object newValue = tryConvert(field, -1, converter, value, cls);
2262            final Object oldValue = field.get(command);
2263            TraceLevel level = TraceLevel.INFO;
2264            String traceMessage = "Setting %s field '%s.%s' to '%5$s' (was '%4$s') for %6$s%n";
2265            if (initialized != null) {
2266                if (initialized.contains(field)) {
2267                    if (!isOverwrittenOptionsAllowed()) {
2268                        throw new OverwrittenOptionException(CommandLine.this, optionDescription("", field, 0) +  " should be specified only once");
2269                    }
2270                    level = TraceLevel.WARN;
2271                    traceMessage = "Overwriting %s field '%s.%s' value '%s' with '%s' for %s%n";
2272                }
2273                initialized.add(field);
2274            }
2275            if (tracer.level.isEnabled(level)) { level.print(tracer, traceMessage, field.getType().getSimpleName(),
2276                        field.getDeclaringClass().getSimpleName(), field.getName(), String.valueOf(oldValue), String.valueOf(newValue), argDescription);
2277            }
2278            field.set(command, newValue);
2279            return result;
2280        }
2281        private int applyValuesToMapField(final Field field,
2282                                          final Class<?> annotation,
2283                                          final Range arity,
2284                                          final Stack<String> args,
2285                                          final Class<?> cls,
2286                                          final String argDescription) throws Exception {
2287            final Class<?>[] classes = getTypeAttribute(field);
2288            if (classes.length < 2) { throw new ParameterException(CommandLine.this, "Field " + field + " needs two types (one for the map key, one for the value) but only has " + classes.length + " types configured."); }
2289            final ITypeConverter<?> keyConverter   = getTypeConverter(classes[0], field);
2290            final ITypeConverter<?> valueConverter = getTypeConverter(classes[1], field);
2291            Map<Object, Object> result = (Map<Object, Object>) field.get(command);
2292            if (result == null) {
2293                result = createMap(cls);
2294                field.set(command, result);
2295            }
2296            final int originalSize = result.size();
2297            consumeMapArguments(field, arity, args, classes, keyConverter, valueConverter, result, argDescription);
2298            return result.size() - originalSize;
2299        }
2300
2301        private void consumeMapArguments(final Field field,
2302                                         final Range arity,
2303                                         final Stack<String> args,
2304                                         final Class<?>[] classes,
2305                                         final ITypeConverter<?> keyConverter,
2306                                         final ITypeConverter<?> valueConverter,
2307                                         final Map<Object, Object> result,
2308                                         final String argDescription) throws Exception {
2309            // first do the arity.min mandatory parameters
2310            for (int i = 0; i < arity.min; i++) {
2311                consumeOneMapArgument(field, arity, args, classes, keyConverter, valueConverter, result, i, argDescription);
2312            }
2313            // now process the varargs if any
2314            for (int i = arity.min; i < arity.max && !args.isEmpty(); i++) {
2315                if (!field.isAnnotationPresent(Parameters.class)) {
2316                    if (commands.containsKey(args.peek()) || isOption(args.peek())) {
2317                        return;
2318                    }
2319                }
2320                consumeOneMapArgument(field, arity, args, classes, keyConverter, valueConverter, result, i, argDescription);
2321            }
2322        }
2323
2324        private void consumeOneMapArgument(final Field field,
2325                                           final Range arity,
2326                                           final Stack<String> args,
2327                                           final Class<?>[] classes,
2328                                           final ITypeConverter<?> keyConverter, final ITypeConverter<?> valueConverter,
2329                                           final Map<Object, Object> result,
2330                                           final int index,
2331                                           final String argDescription) throws Exception {
2332            final String[] values = split(trim(args.pop()), field);
2333            for (final String value : values) {
2334                final String[] keyValue = value.split("=");
2335                if (keyValue.length < 2) {
2336                    final String splitRegex = splitRegex(field);
2337                    if (splitRegex.length() == 0) {
2338                        throw new ParameterException(CommandLine.this, "Value for option " + optionDescription("", field,
2339                                0) + " should be in KEY=VALUE format but was " + value);
2340                    } else {
2341                        throw new ParameterException(CommandLine.this, "Value for option " + optionDescription("", field,
2342                                0) + " should be in KEY=VALUE[" + splitRegex + "KEY=VALUE]... format but was " + value);
2343                    }
2344                }
2345                final Object mapKey =   tryConvert(field, index, keyConverter,   keyValue[0], classes[0]);
2346                final Object mapValue = tryConvert(field, index, valueConverter, keyValue[1], classes[1]);
2347                result.put(mapKey, mapValue);
2348                if (tracer.isInfo()) {tracer.info("Putting [%s : %s] in %s<%s, %s> field '%s.%s' for %s%n", String.valueOf(mapKey), String.valueOf(mapValue),
2349                        result.getClass().getSimpleName(), classes[0].getSimpleName(), classes[1].getSimpleName(), field.getDeclaringClass().getSimpleName(), field.getName(), argDescription);}
2350            }
2351        }
2352
2353        private void checkMaxArityExceeded(final Range arity, final int remainder, final Field field, final String[] values) {
2354            if (values.length <= remainder) { return; }
2355            final String desc = arity.max == remainder ? "" + remainder : arity + ", remainder=" + remainder;
2356            throw new MaxValuesforFieldExceededException(CommandLine.this, optionDescription("", field, -1) +
2357                    " max number of values (" + arity.max + ") exceeded: remainder is " + remainder + " but " +
2358                    values.length + " values were specified: " + Arrays.toString(values));
2359        }
2360
2361        private int applyValuesToArrayField(final Field field,
2362                                            final Class<?> annotation,
2363                                            final Range arity,
2364                                            final Stack<String> args,
2365                                            final Class<?> cls,
2366                                            final String argDescription) throws Exception {
2367            final Object existing = field.get(command);
2368            final int length = existing == null ? 0 : Array.getLength(existing);
2369            final Class<?> type = getTypeAttribute(field)[0];
2370            final List<Object> converted = consumeArguments(field, annotation, arity, args, type, length, argDescription);
2371            final List<Object> newValues = new ArrayList<>();
2372            for (int i = 0; i < length; i++) {
2373                newValues.add(Array.get(existing, i));
2374            }
2375            for (final Object obj : converted) {
2376                if (obj instanceof Collection<?>) {
2377                    newValues.addAll((Collection<?>) obj);
2378                } else {
2379                    newValues.add(obj);
2380                }
2381            }
2382            final Object array = Array.newInstance(type, newValues.size());
2383            field.set(command, array);
2384            for (int i = 0; i < newValues.size(); i++) {
2385                Array.set(array, i, newValues.get(i));
2386            }
2387            return converted.size(); // return how many args were consumed
2388        }
2389
2390        @SuppressWarnings("unchecked")
2391        private int applyValuesToCollectionField(final Field field,
2392                                                 final Class<?> annotation,
2393                                                 final Range arity,
2394                                                 final Stack<String> args,
2395                                                 final Class<?> cls,
2396                                                 final String argDescription) throws Exception {
2397            Collection<Object> collection = (Collection<Object>) field.get(command);
2398            final Class<?> type = getTypeAttribute(field)[0];
2399            final int length = collection == null ? 0 : collection.size();
2400            final List<Object> converted = consumeArguments(field, annotation, arity, args, type, length, argDescription);
2401            if (collection == null) {
2402                collection = createCollection(cls);
2403                field.set(command, collection);
2404            }
2405            for (final Object element : converted) {
2406                if (element instanceof Collection<?>) {
2407                    collection.addAll((Collection<?>) element);
2408                } else {
2409                    collection.add(element);
2410                }
2411            }
2412            return converted.size();
2413        }
2414
2415        private List<Object> consumeArguments(final Field field,
2416                                              final Class<?> annotation,
2417                                              final Range arity,
2418                                              final Stack<String> args,
2419                                              final Class<?> type,
2420                                              final int originalSize,
2421                                              final String argDescription) throws Exception {
2422            final List<Object> result = new ArrayList<>();
2423
2424            // first do the arity.min mandatory parameters
2425            for (int i = 0; i < arity.min; i++) {
2426                consumeOneArgument(field, arity, args, type, result, i, originalSize, argDescription);
2427            }
2428            // now process the varargs if any
2429            for (int i = arity.min; i < arity.max && !args.isEmpty(); i++) {
2430                if (annotation != Parameters.class) { // for vararg Options, we stop if we encounter '--', a command, or another option
2431                    if (commands.containsKey(args.peek()) || isOption(args.peek())) {
2432                        return result;
2433                    }
2434                }
2435                consumeOneArgument(field, arity, args, type, result, i, originalSize, argDescription);
2436            }
2437            return result;
2438        }
2439
2440        private int consumeOneArgument(final Field field,
2441                                       final Range arity,
2442                                       final Stack<String> args,
2443                                       final Class<?> type,
2444                                       final List<Object> result,
2445                                       int index,
2446                                       final int originalSize,
2447                                       final String argDescription) throws Exception {
2448            final String[] values = split(trim(args.pop()), field);
2449            final ITypeConverter<?> converter = getTypeConverter(type, field);
2450
2451            for (int j = 0; j < values.length; j++) {
2452                result.add(tryConvert(field, index, converter, values[j], type));
2453                if (tracer.isInfo()) {
2454                    if (field.getType().isArray()) {
2455                        tracer.info("Adding [%s] to %s[] field '%s.%s' for %s%n", String.valueOf(result.get(result.size() - 1)), type.getSimpleName(), field.getDeclaringClass().getSimpleName(), field.getName(), argDescription);
2456                    } else {
2457                        tracer.info("Adding [%s] to %s<%s> field '%s.%s' for %s%n", String.valueOf(result.get(result.size() - 1)), field.getType().getSimpleName(), type.getSimpleName(), field.getDeclaringClass().getSimpleName(), field.getName(), argDescription);
2458                    }
2459                }
2460            }
2461            //checkMaxArityExceeded(arity, max, field, values);
2462            return ++index;
2463        }
2464
2465        private String splitRegex(final Field field) {
2466            if (field.isAnnotationPresent(Option.class))     { return field.getAnnotation(Option.class).split(); }
2467            if (field.isAnnotationPresent(Parameters.class)) { return field.getAnnotation(Parameters.class).split(); }
2468            return "";
2469        }
2470        private String[] split(final String value, final Field field) {
2471            final String regex = splitRegex(field);
2472            return regex.length() == 0 ? new String[] {value} : value.split(regex);
2473        }
2474
2475        /**
2476         * Called when parsing varargs parameters for a multi-value option.
2477         * When an option is encountered, the remainder should not be interpreted as vararg elements.
2478         * @param arg the string to determine whether it is an option or not
2479         * @return true if it is an option, false otherwise
2480         */
2481        private boolean isOption(final String arg) {
2482            if ("--".equals(arg)) {
2483                return true;
2484            }
2485            // not just arg prefix: we may be in the middle of parsing -xrvfFILE
2486            if (optionName2Field.containsKey(arg)) { // -v or -f or --file (not attached to param or other option)
2487                return true;
2488            }
2489            final int separatorIndex = arg.indexOf(separator);
2490            if (separatorIndex > 0) { // -f=FILE or --file==FILE (attached to param via separator)
2491                if (optionName2Field.containsKey(arg.substring(0, separatorIndex))) {
2492                    return true;
2493                }
2494            }
2495            return (arg.length() > 2 && arg.startsWith("-") && singleCharOption2Field.containsKey(arg.charAt(1)));
2496        }
2497        private Object tryConvert(final Field field, final int index, final ITypeConverter<?> converter, final String value, final Class<?> type)
2498                throws Exception {
2499            try {
2500                return converter.convert(value);
2501            } catch (final TypeConversionException ex) {
2502                throw new ParameterException(CommandLine.this, ex.getMessage() + optionDescription(" for ", field, index));
2503            } catch (final Exception other) {
2504                final String desc = optionDescription(" for ", field, index) + ": " + other;
2505                throw new ParameterException(CommandLine.this, "Could not convert '" + value + "' to " + type.getSimpleName() + desc, other);
2506            }
2507        }
2508
2509        private String optionDescription(final String prefix, final Field field, final int index) {
2510            final Help.IParamLabelRenderer labelRenderer = Help.createMinimalParamLabelRenderer();
2511            String desc = "";
2512            if (field.isAnnotationPresent(Option.class)) {
2513                desc = prefix + "option '" + field.getAnnotation(Option.class).names()[0] + "'";
2514                if (index >= 0) {
2515                    final Range arity = Range.optionArity(field);
2516                    if (arity.max > 1) {
2517                        desc += " at index " + index;
2518                    }
2519                    desc += " (" + labelRenderer.renderParameterLabel(field, Help.Ansi.OFF, Collections.<IStyle>emptyList()) + ")";
2520                }
2521            } else if (field.isAnnotationPresent(Parameters.class)) {
2522                final Range indexRange = Range.parameterIndex(field);
2523                final Text label = labelRenderer.renderParameterLabel(field, Help.Ansi.OFF, Collections.<IStyle>emptyList());
2524                desc = prefix + "positional parameter at index " + indexRange + " (" + label + ")";
2525            }
2526            return desc;
2527        }
2528
2529        private boolean isAnyHelpRequested() { return isHelpRequested || versionHelpRequested || usageHelpRequested; }
2530
2531        private void updateHelpRequested(final Field field) {
2532            if (field.isAnnotationPresent(Option.class)) {
2533                isHelpRequested                       |= is(field, "help", field.getAnnotation(Option.class).help());
2534                CommandLine.this.versionHelpRequested |= is(field, "versionHelp", field.getAnnotation(Option.class).versionHelp());
2535                CommandLine.this.usageHelpRequested   |= is(field, "usageHelp", field.getAnnotation(Option.class).usageHelp());
2536            }
2537        }
2538        private boolean is(final Field f, final String description, final boolean value) {
2539            if (value) { if (tracer.isInfo()) {tracer.info("Field '%s.%s' has '%s' annotation: not validating required fields%n", f.getDeclaringClass().getSimpleName(), f.getName(), description); }}
2540            return value;
2541        }
2542        @SuppressWarnings("unchecked")
2543        private Collection<Object> createCollection(final Class<?> collectionClass) throws Exception {
2544            if (collectionClass.isInterface()) {
2545                if (SortedSet.class.isAssignableFrom(collectionClass)) {
2546                    return new TreeSet<>();
2547                } else if (Set.class.isAssignableFrom(collectionClass)) {
2548                    return new LinkedHashSet<>();
2549                } else if (Queue.class.isAssignableFrom(collectionClass)) {
2550                    return new LinkedList<>(); // ArrayDeque is only available since 1.6
2551                }
2552                return new ArrayList<>();
2553            }
2554            // custom Collection implementation class must have default constructor
2555            return (Collection<Object>) collectionClass.newInstance();
2556        }
2557        private Map<Object, Object> createMap(final Class<?> mapClass) throws Exception {
2558            try { // if it is an implementation class, instantiate it
2559                return (Map<Object, Object>) mapClass.newInstance();
2560            } catch (final Exception ignored) {}
2561            return new LinkedHashMap<>();
2562        }
2563        private ITypeConverter<?> getTypeConverter(final Class<?> type, final Field field) {
2564            final ITypeConverter<?> result = converterRegistry.get(type);
2565            if (result != null) {
2566                return result;
2567            }
2568            if (type.isEnum()) {
2569                return new ITypeConverter<Object>() {
2570                    @Override
2571                    @SuppressWarnings("unchecked")
2572                    public Object convert(final String value) throws Exception {
2573                        return Enum.valueOf((Class<Enum>) type, value);
2574                    }
2575                };
2576            }
2577            throw new MissingTypeConverterException(CommandLine.this, "No TypeConverter registered for " + type.getName() + " of field " + field);
2578        }
2579
2580        private void assertNoMissingParameters(final Field field, final int arity, final Stack<String> args) {
2581            if (arity > args.size()) {
2582                if (arity == 1) {
2583                    if (field.isAnnotationPresent(Option.class)) {
2584                        throw new MissingParameterException(CommandLine.this, "Missing required parameter for " +
2585                                optionDescription("", field, 0));
2586                    }
2587                    final Range indexRange = Range.parameterIndex(field);
2588                    final Help.IParamLabelRenderer labelRenderer = Help.createMinimalParamLabelRenderer();
2589                    String sep = "";
2590                    String names = "";
2591                    int count = 0;
2592                    for (int i = indexRange.min; i < positionalParametersFields.size(); i++) {
2593                        if (Range.parameterArity(positionalParametersFields.get(i)).min > 0) {
2594                            names += sep + labelRenderer.renderParameterLabel(positionalParametersFields.get(i),
2595                                    Help.Ansi.OFF, Collections.<IStyle>emptyList());
2596                            sep = ", ";
2597                            count++;
2598                        }
2599                    }
2600                    String msg = "Missing required parameter";
2601                    final Range paramArity = Range.parameterArity(field);
2602                    if (paramArity.isVariable) {
2603                        msg += "s at positions " + indexRange + ": ";
2604                    } else {
2605                        msg += (count > 1 ? "s: " : ": ");
2606                    }
2607                    throw new MissingParameterException(CommandLine.this, msg + names);
2608                }
2609                if (args.isEmpty()) {
2610                    throw new MissingParameterException(CommandLine.this, optionDescription("", field, 0) +
2611                            " requires at least " + arity + " values, but none were specified.");
2612                }
2613                throw new MissingParameterException(CommandLine.this, optionDescription("", field, 0) +
2614                        " requires at least " + arity + " values, but only " + args.size() + " were specified: " + reverse(args));
2615            }
2616        }
2617        private String trim(final String value) {
2618            return unquote(value);
2619        }
2620
2621        private String unquote(final String value) {
2622            return value == null
2623                    ? null
2624                    : (value.length() > 1 && value.startsWith("\"") && value.endsWith("\""))
2625                        ? value.substring(1, value.length() - 1)
2626                        : value;
2627        }
2628    }
2629    private static class PositionalParametersSorter implements Comparator<Field> {
2630        @Override
2631        public int compare(final Field o1, final Field o2) {
2632            final int result = Range.parameterIndex(o1).compareTo(Range.parameterIndex(o2));
2633            return (result == 0) ? Range.parameterArity(o1).compareTo(Range.parameterArity(o2)) : result;
2634        }
2635    }
2636    /**
2637     * Inner class to group the built-in {@link ITypeConverter} implementations.
2638     */
2639    private static class BuiltIn {
2640        static class PathConverter implements ITypeConverter<Path> {
2641            @Override public Path convert(final String value) { return Paths.get(value); }
2642        }
2643        static class StringConverter implements ITypeConverter<String> {
2644            @Override
2645            public String convert(final String value) { return value; }
2646        }
2647        static class StringBuilderConverter implements ITypeConverter<StringBuilder> {
2648            @Override
2649            public StringBuilder convert(final String value) { return new StringBuilder(value); }
2650        }
2651        static class CharSequenceConverter implements ITypeConverter<CharSequence> {
2652            @Override
2653            public String convert(final String value) { return value; }
2654        }
2655        /** Converts text to a {@code Byte} by delegating to {@link Byte#valueOf(String)}.*/
2656        static class ByteConverter implements ITypeConverter<Byte> {
2657            @Override
2658            public Byte convert(final String value) { return Byte.valueOf(value); }
2659        }
2660        /** Converts {@code "true"} or {@code "false"} to a {@code Boolean}. Other values result in a ParameterException.*/
2661        static class BooleanConverter implements ITypeConverter<Boolean> {
2662            @Override
2663            public Boolean convert(final String value) {
2664                if ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value)) {
2665                    return Boolean.parseBoolean(value);
2666                } else {
2667                    throw new TypeConversionException("'" + value + "' is not a boolean");
2668                }
2669            }
2670        }
2671        static class CharacterConverter implements ITypeConverter<Character> {
2672            @Override
2673            public Character convert(final String value) {
2674                if (value.length() > 1) {
2675                    throw new TypeConversionException("'" + value + "' is not a single character");
2676                }
2677                return value.charAt(0);
2678            }
2679        }
2680        /** Converts text to a {@code Short} by delegating to {@link Short#valueOf(String)}.*/
2681        static class ShortConverter implements ITypeConverter<Short> {
2682            @Override
2683            public Short convert(final String value) { return Short.valueOf(value); }
2684        }
2685        /** Converts text to an {@code Integer} by delegating to {@link Integer#valueOf(String)}.*/
2686        static class IntegerConverter implements ITypeConverter<Integer> {
2687            @Override
2688            public Integer convert(final String value) { return Integer.valueOf(value); }
2689        }
2690        /** Converts text to a {@code Long} by delegating to {@link Long#valueOf(String)}.*/
2691        static class LongConverter implements ITypeConverter<Long> {
2692            @Override
2693            public Long convert(final String value) { return Long.valueOf(value); }
2694        }
2695        static class FloatConverter implements ITypeConverter<Float> {
2696            @Override
2697            public Float convert(final String value) { return Float.valueOf(value); }
2698        }
2699        static class DoubleConverter implements ITypeConverter<Double> {
2700            @Override
2701            public Double convert(final String value) { return Double.valueOf(value); }
2702        }
2703        static class FileConverter implements ITypeConverter<File> {
2704            @Override
2705            public File convert(final String value) { return new File(value); }
2706        }
2707        static class URLConverter implements ITypeConverter<URL> {
2708            @Override
2709            public URL convert(final String value) throws MalformedURLException { return new URL(value); }
2710        }
2711        static class URIConverter implements ITypeConverter<URI> {
2712            @Override
2713            public URI convert(final String value) throws URISyntaxException { return new URI(value); }
2714        }
2715        /** Converts text in {@code yyyy-mm-dd} format to a {@code java.util.Date}. ParameterException on failure. */
2716        static class ISO8601DateConverter implements ITypeConverter<Date> {
2717            @Override
2718            public Date convert(final String value) {
2719                try {
2720                    return new SimpleDateFormat("yyyy-MM-dd").parse(value);
2721                } catch (final ParseException e) {
2722                    throw new TypeConversionException("'" + value + "' is not a yyyy-MM-dd date");
2723                }
2724            }
2725        }
2726        /** Converts text in any of the following formats to a {@code java.sql.Time}: {@code HH:mm}, {@code HH:mm:ss},
2727         * {@code HH:mm:ss.SSS}, {@code HH:mm:ss,SSS}. Other formats result in a ParameterException. */
2728        static class ISO8601TimeConverter implements ITypeConverter<Time> {
2729            @Override
2730            public Time convert(final String value) {
2731                try {
2732                    if (value.length() <= 5) {
2733                        return new Time(new SimpleDateFormat("HH:mm").parse(value).getTime());
2734                    } else if (value.length() <= 8) {
2735                        return new Time(new SimpleDateFormat("HH:mm:ss").parse(value).getTime());
2736                    } else if (value.length() <= 12) {
2737                        try {
2738                            return new Time(new SimpleDateFormat("HH:mm:ss.SSS").parse(value).getTime());
2739                        } catch (final ParseException e2) {
2740                            return new Time(new SimpleDateFormat("HH:mm:ss,SSS").parse(value).getTime());
2741                        }
2742                    }
2743                } catch (final ParseException ignored) {
2744                    // ignored because we throw a ParameterException below
2745                }
2746                throw new TypeConversionException("'" + value + "' is not a HH:mm[:ss[.SSS]] time");
2747            }
2748        }
2749        static class BigDecimalConverter implements ITypeConverter<BigDecimal> {
2750            @Override
2751            public BigDecimal convert(final String value) { return new BigDecimal(value); }
2752        }
2753        static class BigIntegerConverter implements ITypeConverter<BigInteger> {
2754            @Override
2755            public BigInteger convert(final String value) { return new BigInteger(value); }
2756        }
2757        static class CharsetConverter implements ITypeConverter<Charset> {
2758            @Override
2759            public Charset convert(final String s) { return Charset.forName(s); }
2760        }
2761        /** Converts text to a {@code InetAddress} by delegating to {@link InetAddress#getByName(String)}. */
2762        static class InetAddressConverter implements ITypeConverter<InetAddress> {
2763            @Override
2764            public InetAddress convert(final String s) throws Exception { return InetAddress.getByName(s); }
2765        }
2766        static class PatternConverter implements ITypeConverter<Pattern> {
2767            @Override
2768            public Pattern convert(final String s) { return Pattern.compile(s); }
2769        }
2770        static class UUIDConverter implements ITypeConverter<UUID> {
2771            @Override
2772            public UUID convert(final String s) throws Exception { return UUID.fromString(s); }
2773        }
2774        private BuiltIn() {} // private constructor: never instantiate
2775    }
2776
2777    /**
2778     * A collection of methods and inner classes that provide fine-grained control over the contents and layout of
2779     * the usage help message to display to end users when help is requested or invalid input values were specified.
2780     * <h3>Layered API</h3>
2781     * <p>The {@link Command} annotation provides the easiest way to customize usage help messages. See
2782     * the <a href="https://remkop.github.io/picocli/index.html#_usage_help">Manual</a> for details.</p>
2783     * <p>This Help class provides high-level functions to create sections of the usage help message and headings
2784     * for these sections. Instead of calling the {@link CommandLine#usage(PrintStream, CommandLine.Help.ColorScheme)}
2785     * method, application authors may want to create a custom usage help message by reorganizing sections in a
2786     * different order and/or adding custom sections.</p>
2787     * <p>Finally, the Help class contains inner classes and interfaces that can be used to create custom help messages.</p>
2788     * <h4>IOptionRenderer and IParameterRenderer</h4>
2789     * <p>Renders a field annotated with {@link Option} or {@link Parameters} to an array of {@link Text} values.
2790     * By default, these values are</p><ul>
2791     * <li>mandatory marker character (if the option/parameter is {@link Option#required() required})</li>
2792     * <li>short option name (empty for parameters)</li>
2793     * <li>comma or empty (empty for parameters)</li>
2794     * <li>long option names (the parameter {@link IParamLabelRenderer label} for parameters)</li>
2795     * <li>description</li>
2796     * </ul>
2797     * <p>Other components rely on this ordering.</p>
2798     * <h4>Layout</h4>
2799     * <p>Delegates to the renderers to create {@link Text} values for the annotated fields, and uses a
2800     * {@link TextTable} to display these values in tabular format. Layout is responsible for deciding which values
2801     * to display where in the table. By default, Layout shows one option or parameter per table row.</p>
2802     * <h4>TextTable</h4>
2803     * <p>Responsible for spacing out {@link Text} values according to the {@link Column} definitions the table was
2804     * created with. Columns have a width, indentation, and an overflow policy that decides what to do if a value is
2805     * longer than the column's width.</p>
2806     * <h4>Text</h4>
2807     * <p>Encapsulates rich text with styles and colors in a way that other components like {@link TextTable} are
2808     * unaware of the embedded ANSI escape codes.</p>
2809     */
2810    public static class Help {
2811        /** Constant String holding the default program name: {@value} */
2812        protected static final String DEFAULT_COMMAND_NAME = "<main class>";
2813
2814        /** Constant String holding the default string that separates options from option parameters: {@value} */
2815        protected static final String DEFAULT_SEPARATOR = "=";
2816
2817        private final static int usageHelpWidth = 80;
2818        private final static int optionsColumnWidth = 2 + 2 + 1 + 24;
2819        private final Object command;
2820        private final Map<String, Help> commands = new LinkedHashMap<>();
2821        final ColorScheme colorScheme;
2822
2823        /** Immutable list of fields annotated with {@link Option}, in declaration order. */
2824        public final List<Field> optionFields;
2825
2826        /** Immutable list of fields annotated with {@link Parameters}, or an empty list if no such field exists. */
2827        public final List<Field> positionalParametersFields;
2828
2829        /** The String to use as the separator between options and option parameters. {@code "="} by default,
2830         * initialized from {@link Command#separator()} if defined.
2831         * @see #parameterLabelRenderer */
2832        public String separator;
2833
2834        /** The String to use as the program name in the synopsis line of the help message.
2835         * {@link #DEFAULT_COMMAND_NAME} by default, initialized from {@link Command#name()} if defined. */
2836        public String commandName = DEFAULT_COMMAND_NAME;
2837
2838        /** Optional text lines to use as the description of the help message, displayed between the synopsis and the
2839         * options list. Initialized from {@link Command#description()} if the {@code Command} annotation is present,
2840         * otherwise this is an empty array and the help message has no description.
2841         * Applications may programmatically set this field to create a custom help message. */
2842        public String[] description = {};
2843
2844        /** Optional custom synopsis lines to use instead of the auto-generated synopsis.
2845         * Initialized from {@link Command#customSynopsis()} if the {@code Command} annotation is present,
2846         * otherwise this is an empty array and the synopsis is generated.
2847         * Applications may programmatically set this field to create a custom help message. */
2848        public String[] customSynopsis = {};
2849
2850        /** Optional header lines displayed at the top of the help message. For subcommands, the first header line is
2851         * displayed in the list of commands. Values are initialized from {@link Command#header()}
2852         * if the {@code Command} annotation is present, otherwise this is an empty array and the help message has no
2853         * header. Applications may programmatically set this field to create a custom help message. */
2854        public String[] header = {};
2855
2856        /** Optional footer text lines displayed at the bottom of the help message. Initialized from
2857         * {@link Command#footer()} if the {@code Command} annotation is present, otherwise this is an empty array and
2858         * the help message has no footer.
2859         * Applications may programmatically set this field to create a custom help message. */
2860        public String[] footer = {};
2861
2862        /** Option and positional parameter value label renderer used for the synopsis line(s) and the option list.
2863         * By default initialized to the result of {@link #createDefaultParamLabelRenderer()}, which takes a snapshot
2864         * of the {@link #separator} at construction time. If the separator is modified after Help construction, you
2865         * may need to re-initialize this field by calling {@link #createDefaultParamLabelRenderer()} again. */
2866        public IParamLabelRenderer parameterLabelRenderer;
2867
2868        /** If {@code true}, the synopsis line(s) will show an abbreviated synopsis without detailed option names. */
2869        public Boolean abbreviateSynopsis;
2870
2871        /** If {@code true}, the options list is sorted alphabetically. */
2872        public Boolean sortOptions;
2873
2874        /** If {@code true}, the options list will show default values for all options except booleans. */
2875        public Boolean showDefaultValues;
2876
2877        /** Character used to prefix required options in the options list. */
2878        public Character requiredOptionMarker;
2879
2880        /** Optional heading preceding the header section. Initialized from {@link Command#headerHeading()}, or null. */
2881        public String headerHeading;
2882
2883        /** Optional heading preceding the synopsis. Initialized from {@link Command#synopsisHeading()}, {@code "Usage: "} by default. */
2884        public String synopsisHeading;
2885
2886        /** Optional heading preceding the description section. Initialized from {@link Command#descriptionHeading()}, or null. */
2887        public String descriptionHeading;
2888
2889        /** Optional heading preceding the parameter list. Initialized from {@link Command#parameterListHeading()}, or null. */
2890        public String parameterListHeading;
2891
2892        /** Optional heading preceding the options list. Initialized from {@link Command#optionListHeading()}, or null. */
2893        public String optionListHeading;
2894
2895        /** Optional heading preceding the subcommand list. Initialized from {@link Command#commandListHeading()}. {@code "Commands:%n"} by default. */
2896        public String commandListHeading;
2897
2898        /** Optional heading preceding the footer section. Initialized from {@link Command#footerHeading()}, or null. */
2899        public String footerHeading;
2900
2901        /** Constructs a new {@code Help} instance with a default color scheme, initialized from annotatations
2902         * on the specified class and superclasses.
2903         * @param command the annotated object to create usage help for */
2904        public Help(final Object command) {
2905            this(command, Ansi.AUTO);
2906        }
2907
2908        /** Constructs a new {@code Help} instance with a default color scheme, initialized from annotatations
2909         * on the specified class and superclasses.
2910         * @param command the annotated object to create usage help for
2911         * @param ansi whether to emit ANSI escape codes or not */
2912        public Help(final Object command, final Ansi ansi) {
2913            this(command, defaultColorScheme(ansi));
2914        }
2915
2916        /** Constructs a new {@code Help} instance with the specified color scheme, initialized from annotatations
2917         * on the specified class and superclasses.
2918         * @param command the annotated object to create usage help for
2919         * @param colorScheme the color scheme to use */
2920        public Help(final Object command, final ColorScheme colorScheme) {
2921            this.command = Assert.notNull(command, "command");
2922            this.colorScheme = Assert.notNull(colorScheme, "colorScheme").applySystemProperties();
2923            final List<Field> options = new ArrayList<>();
2924            final List<Field> operands = new ArrayList<>();
2925            Class<?> cls = command.getClass();
2926            while (cls != null) {
2927                for (final Field field : cls.getDeclaredFields()) {
2928                    field.setAccessible(true);
2929                    if (field.isAnnotationPresent(Option.class)) {
2930                        final Option option = field.getAnnotation(Option.class);
2931                        if (!option.hidden()) { // hidden options should not appear in usage help
2932                            // TODO remember longest concatenated option string length (issue #45)
2933                            options.add(field);
2934                        }
2935                    }
2936                    if (field.isAnnotationPresent(Parameters.class)) {
2937                        operands.add(field);
2938                    }
2939                }
2940                // superclass values should not overwrite values if both class and superclass have a @Command annotation
2941                if (cls.isAnnotationPresent(Command.class)) {
2942                    final Command cmd = cls.getAnnotation(Command.class);
2943                    if (DEFAULT_COMMAND_NAME.equals(commandName)) {
2944                        commandName = cmd.name();
2945                    }
2946                    separator = (separator == null) ? cmd.separator() : separator;
2947                    abbreviateSynopsis = (abbreviateSynopsis == null) ? cmd.abbreviateSynopsis() : abbreviateSynopsis;
2948                    sortOptions = (sortOptions == null) ? cmd.sortOptions() : sortOptions;
2949                    requiredOptionMarker = (requiredOptionMarker == null) ? cmd.requiredOptionMarker() : requiredOptionMarker;
2950                    showDefaultValues = (showDefaultValues == null) ? cmd.showDefaultValues() : showDefaultValues;
2951                    customSynopsis = empty(customSynopsis) ? cmd.customSynopsis() : customSynopsis;
2952                    description = empty(description) ? cmd.description() : description;
2953                    header = empty(header) ? cmd.header() : header;
2954                    footer = empty(footer) ? cmd.footer() : footer;
2955                    headerHeading = empty(headerHeading) ? cmd.headerHeading() : headerHeading;
2956                    synopsisHeading = empty(synopsisHeading) || "Usage: ".equals(synopsisHeading) ? cmd.synopsisHeading() : synopsisHeading;
2957                    descriptionHeading = empty(descriptionHeading) ? cmd.descriptionHeading() : descriptionHeading;
2958                    parameterListHeading = empty(parameterListHeading) ? cmd.parameterListHeading() : parameterListHeading;
2959                    optionListHeading = empty(optionListHeading) ? cmd.optionListHeading() : optionListHeading;
2960                    commandListHeading = empty(commandListHeading) || "Commands:%n".equals(commandListHeading) ? cmd.commandListHeading() : commandListHeading;
2961                    footerHeading = empty(footerHeading) ? cmd.footerHeading() : footerHeading;
2962                }
2963                cls = cls.getSuperclass();
2964            }
2965            sortOptions =          (sortOptions == null)          ? true : sortOptions;
2966            abbreviateSynopsis =   (abbreviateSynopsis == null)   ? false : abbreviateSynopsis;
2967            requiredOptionMarker = (requiredOptionMarker == null) ? ' ' : requiredOptionMarker;
2968            showDefaultValues =    (showDefaultValues == null)    ? false : showDefaultValues;
2969            synopsisHeading =      (synopsisHeading == null)      ? "Usage: " : synopsisHeading;
2970            commandListHeading =   (commandListHeading == null)   ? "Commands:%n" : commandListHeading;
2971            separator =            (separator == null)            ? DEFAULT_SEPARATOR : separator;
2972            parameterLabelRenderer = createDefaultParamLabelRenderer(); // uses help separator
2973            Collections.sort(operands, new PositionalParametersSorter());
2974            positionalParametersFields = Collections.unmodifiableList(operands);
2975            optionFields                 = Collections.unmodifiableList(options);
2976        }
2977
2978        /** Registers all specified subcommands with this Help.
2979         * @param commands maps the command names to the associated CommandLine object
2980         * @return this Help instance (for method chaining)
2981         * @see CommandLine#getSubcommands()
2982         */
2983        public Help addAllSubcommands(final Map<String, CommandLine> commands) {
2984            if (commands != null) {
2985                for (final Map.Entry<String, CommandLine> entry : commands.entrySet()) {
2986                    addSubcommand(entry.getKey(), entry.getValue().getCommand());
2987                }
2988            }
2989            return this;
2990        }
2991
2992        /** Registers the specified subcommand with this Help.
2993         * @param commandName the name of the subcommand to display in the usage message
2994         * @param command the annotated object to get more information from
2995         * @return this Help instance (for method chaining)
2996         */
2997        public Help addSubcommand(final String commandName, final Object command) {
2998            commands.put(commandName, new Help(command));
2999            return this;
3000        }
3001
3002        /** Returns a synopsis for the command without reserving space for the synopsis heading.
3003         * @return a synopsis
3004         * @see #abbreviatedSynopsis()
3005         * @see #detailedSynopsis(Comparator, boolean)
3006         * @deprecated use {@link #synopsis(int)} instead
3007         */
3008        @Deprecated
3009        public String synopsis() { return synopsis(0); }
3010
3011        /**
3012         * Returns a synopsis for the command, reserving the specified space for the synopsis heading.
3013         * @param synopsisHeadingLength the length of the synopsis heading that will be displayed on the same line
3014         * @return a synopsis
3015         * @see #abbreviatedSynopsis()
3016         * @see #detailedSynopsis(Comparator, boolean)
3017         * @see #synopsisHeading
3018         */
3019        public String synopsis(final int synopsisHeadingLength) {
3020            if (!empty(customSynopsis)) { return customSynopsis(); }
3021            return abbreviateSynopsis ? abbreviatedSynopsis()
3022                    : detailedSynopsis(synopsisHeadingLength, createShortOptionArityAndNameComparator(), true);
3023        }
3024
3025        /** Generates a generic synopsis like {@code <command name> [OPTIONS] [PARAM1 [PARAM2]...]}, omitting parts
3026         * that don't apply to the command (e.g., does not show [OPTIONS] if the command has no options).
3027         * @return a generic synopsis */
3028        public String abbreviatedSynopsis() {
3029            final StringBuilder sb = new StringBuilder();
3030            if (!optionFields.isEmpty()) { // only show if annotated object actually has options
3031                sb.append(" [OPTIONS]");
3032            }
3033            // sb.append(" [--] "); // implied
3034            for (final Field positionalParam : positionalParametersFields) {
3035                if (!positionalParam.getAnnotation(Parameters.class).hidden()) {
3036                    sb.append(' ').append(parameterLabelRenderer.renderParameterLabel(positionalParam, ansi(), colorScheme.parameterStyles));
3037                }
3038            }
3039            return colorScheme.commandText(commandName).toString()
3040                    + (sb.toString()) + System.getProperty("line.separator");
3041        }
3042        /** Generates a detailed synopsis message showing all options and parameters. Follows the unix convention of
3043         * showing optional options and parameters in square brackets ({@code [ ]}).
3044         * @param optionSort comparator to sort options or {@code null} if options should not be sorted
3045         * @param clusterBooleanOptions {@code true} if boolean short options should be clustered into a single string
3046         * @return a detailed synopsis
3047         * @deprecated use {@link #detailedSynopsis(int, Comparator, boolean)} instead. */
3048        @Deprecated
3049        public String detailedSynopsis(final Comparator<Field> optionSort, final boolean clusterBooleanOptions) {
3050            return detailedSynopsis(0, optionSort, clusterBooleanOptions);
3051        }
3052
3053        /** Generates a detailed synopsis message showing all options and parameters. Follows the unix convention of
3054         * showing optional options and parameters in square brackets ({@code [ ]}).
3055         * @param synopsisHeadingLength the length of the synopsis heading that will be displayed on the same line
3056         * @param optionSort comparator to sort options or {@code null} if options should not be sorted
3057         * @param clusterBooleanOptions {@code true} if boolean short options should be clustered into a single string
3058         * @return a detailed synopsis */
3059        public String detailedSynopsis(final int synopsisHeadingLength, final Comparator<Field> optionSort, final boolean clusterBooleanOptions) {
3060            Text optionText = ansi().new Text(0);
3061            final List<Field> fields = new ArrayList<>(optionFields); // iterate in declaration order
3062            if (optionSort != null) {
3063                Collections.sort(fields, optionSort);// iterate in specified sort order
3064            }
3065            if (clusterBooleanOptions) { // cluster all short boolean options into a single string
3066                final List<Field> booleanOptions = new ArrayList<>();
3067                final StringBuilder clusteredRequired = new StringBuilder("-");
3068                final StringBuilder clusteredOptional = new StringBuilder("-");
3069                for (final Field field : fields) {
3070                    if (field.getType() == boolean.class || field.getType() == Boolean.class) {
3071                        final Option option = field.getAnnotation(Option.class);
3072                        final String shortestName = ShortestFirst.sort(option.names())[0];
3073                        if (shortestName.length() == 2 && shortestName.startsWith("-")) {
3074                            booleanOptions.add(field);
3075                            if (option.required()) {
3076                                clusteredRequired.append(shortestName.substring(1));
3077                            } else {
3078                                clusteredOptional.append(shortestName.substring(1));
3079                            }
3080                        }
3081                    }
3082                }
3083                fields.removeAll(booleanOptions);
3084                if (clusteredRequired.length() > 1) { // initial length was 1
3085                    optionText = optionText.append(" ").append(colorScheme.optionText(clusteredRequired.toString()));
3086                }
3087                if (clusteredOptional.length() > 1) { // initial length was 1
3088                    optionText = optionText.append(" [").append(colorScheme.optionText(clusteredOptional.toString())).append("]");
3089                }
3090            }
3091            for (final Field field : fields) {
3092                final Option option = field.getAnnotation(Option.class);
3093                if (!option.hidden()) {
3094                    if (option.required()) {
3095                        optionText = appendOptionSynopsis(optionText, field, ShortestFirst.sort(option.names())[0], " ", "");
3096                        if (isMultiValue(field)) {
3097                            optionText = appendOptionSynopsis(optionText, field, ShortestFirst.sort(option.names())[0], " [", "]...");
3098                        }
3099                    } else {
3100                        optionText = appendOptionSynopsis(optionText, field, ShortestFirst.sort(option.names())[0], " [", "]");
3101                        if (isMultiValue(field)) {
3102                            optionText = optionText.append("...");
3103                        }
3104                    }
3105                }
3106            }
3107            for (final Field positionalParam : positionalParametersFields) {
3108                if (!positionalParam.getAnnotation(Parameters.class).hidden()) {
3109                    optionText = optionText.append(" ");
3110                    final Text label = parameterLabelRenderer.renderParameterLabel(positionalParam, colorScheme.ansi(), colorScheme.parameterStyles);
3111                    optionText = optionText.append(label);
3112                }
3113            }
3114            // Fix for #142: first line of synopsis overshoots max. characters
3115            final int firstColumnLength = commandName.length() + synopsisHeadingLength;
3116
3117            // synopsis heading ("Usage: ") may be on the same line, so adjust column width
3118            final TextTable textTable = new TextTable(ansi(), firstColumnLength, usageHelpWidth - firstColumnLength);
3119            textTable.indentWrappedLines = 1; // don't worry about first line: options (2nd column) always start with a space
3120
3121            // right-adjust the command name by length of synopsis heading
3122            final Text PADDING = Ansi.OFF.new Text(stringOf('X', synopsisHeadingLength));
3123            textTable.addRowValues(PADDING.append(colorScheme.commandText(commandName)), optionText);
3124            return textTable.toString().substring(synopsisHeadingLength); // cut off leading synopsis heading spaces
3125        }
3126
3127        private Text appendOptionSynopsis(final Text optionText, final Field field, final String optionName, final String prefix, final String suffix) {
3128            final Text optionParamText = parameterLabelRenderer.renderParameterLabel(field, colorScheme.ansi(), colorScheme.optionParamStyles);
3129            return optionText.append(prefix)
3130                    .append(colorScheme.optionText(optionName))
3131                    .append(optionParamText)
3132                    .append(suffix);
3133        }
3134
3135        /** Returns the number of characters the synopsis heading will take on the same line as the synopsis.
3136         * @return the number of characters the synopsis heading will take on the same line as the synopsis.
3137         * @see #detailedSynopsis(int, Comparator, boolean)
3138         */
3139        public int synopsisHeadingLength() {
3140            final String[] lines = Ansi.OFF.new Text(synopsisHeading).toString().split("\\r?\\n|\\r|%n", -1);
3141            return lines[lines.length - 1].length();
3142        }
3143        /**
3144         * <p>Returns a description of the {@linkplain Option options} supported by the application.
3145         * This implementation {@linkplain #createShortOptionNameComparator() sorts options alphabetically}, and shows
3146         * only the {@linkplain Option#hidden() non-hidden} options in a {@linkplain TextTable tabular format}
3147         * using the {@linkplain #createDefaultOptionRenderer() default renderer} and {@linkplain Layout default layout}.</p>
3148         * @return the fully formatted option list
3149         * @see #optionList(Layout, Comparator, IParamLabelRenderer)
3150         */
3151        public String optionList() {
3152            final Comparator<Field> sortOrder = sortOptions == null || sortOptions.booleanValue()
3153                    ? createShortOptionNameComparator()
3154                    : null;
3155            return optionList(createDefaultLayout(), sortOrder, parameterLabelRenderer);
3156        }
3157
3158        /** Sorts all {@code Options} with the specified {@code comparator} (if the comparator is non-{@code null}),
3159         * then {@linkplain Layout#addOption(Field, CommandLine.Help.IParamLabelRenderer) adds} all non-hidden options to the
3160         * specified TextTable and returns the result of TextTable.toString().
3161         * @param layout responsible for rendering the option list
3162         * @param optionSort determines in what order {@code Options} should be listed. Declared order if {@code null}
3163         * @param valueLabelRenderer used for options with a parameter
3164         * @return the fully formatted option list
3165         */
3166        public String optionList(final Layout layout, final Comparator<Field> optionSort, final IParamLabelRenderer valueLabelRenderer) {
3167            final List<Field> fields = new ArrayList<>(optionFields); // options are stored in order of declaration
3168            if (optionSort != null) {
3169                Collections.sort(fields, optionSort); // default: sort options ABC
3170            }
3171            layout.addOptions(fields, valueLabelRenderer);
3172            return layout.toString();
3173        }
3174
3175        /**
3176         * Returns the section of the usage help message that lists the parameters with their descriptions.
3177         * @return the section of the usage help message that lists the parameters
3178         */
3179        public String parameterList() {
3180            return parameterList(createDefaultLayout(), parameterLabelRenderer);
3181        }
3182        /**
3183         * Returns the section of the usage help message that lists the parameters with their descriptions.
3184         * @param layout the layout to use
3185         * @param paramLabelRenderer for rendering parameter names
3186         * @return the section of the usage help message that lists the parameters
3187         */
3188        public String parameterList(final Layout layout, final IParamLabelRenderer paramLabelRenderer) {
3189            layout.addPositionalParameters(positionalParametersFields, paramLabelRenderer);
3190            return layout.toString();
3191        }
3192
3193        private static String heading(final Ansi ansi, final String values, final Object... params) {
3194            final StringBuilder sb = join(ansi, new String[] {values}, new StringBuilder(), params);
3195            String result = sb.toString();
3196            result = result.endsWith(System.getProperty("line.separator"))
3197                    ? result.substring(0, result.length() - System.getProperty("line.separator").length()) : result;
3198            return result + new String(spaces(countTrailingSpaces(values)));
3199        }
3200        private static char[] spaces(final int length) { final char[] result = new char[length]; Arrays.fill(result, ' '); return result; }
3201        private static int countTrailingSpaces(final String str) {
3202            if (str == null) {return 0;}
3203            int trailingSpaces = 0;
3204            for (int i = str.length() - 1; i >= 0 && str.charAt(i) == ' '; i--) { trailingSpaces++; }
3205            return trailingSpaces;
3206        }
3207
3208        /** Formats each of the specified values and appends it to the specified StringBuilder.
3209         * @param ansi whether the result should contain ANSI escape codes or not
3210         * @param values the values to format and append to the StringBuilder
3211         * @param sb the StringBuilder to collect the formatted strings
3212         * @param params the parameters to pass to the format method when formatting each value
3213         * @return the specified StringBuilder */
3214        public static StringBuilder join(final Ansi ansi, final String[] values, final StringBuilder sb, final Object... params) {
3215            if (values != null) {
3216                final TextTable table = new TextTable(ansi, usageHelpWidth);
3217                table.indentWrappedLines = 0;
3218                for (final String summaryLine : values) {
3219                    final Text[] lines = ansi.new Text(format(summaryLine, params)).splitLines();
3220                    for (final Text line : lines) {  table.addRowValues(line); }
3221                }
3222                table.toString(sb);
3223            }
3224            return sb;
3225        }
3226        private static String format(final String formatString,  final Object... params) {
3227            return formatString == null ? "" : String.format(formatString, params);
3228        }
3229        /** Returns command custom synopsis as a string. A custom synopsis can be zero or more lines, and can be
3230         * specified declaratively with the {@link Command#customSynopsis()} annotation attribute or programmatically
3231         * by setting the Help instance's {@link Help#customSynopsis} field.
3232         * @param params Arguments referenced by the format specifiers in the synopsis strings
3233         * @return the custom synopsis lines combined into a single String (which may be empty)
3234         */
3235        public String customSynopsis(final Object... params) {
3236            return join(ansi(), customSynopsis, new StringBuilder(), params).toString();
3237        }
3238        /** Returns command description text as a string. Description text can be zero or more lines, and can be specified
3239         * declaratively with the {@link Command#description()} annotation attribute or programmatically by
3240         * setting the Help instance's {@link Help#description} field.
3241         * @param params Arguments referenced by the format specifiers in the description strings
3242         * @return the description lines combined into a single String (which may be empty)
3243         */
3244        public String description(final Object... params) {
3245            return join(ansi(), description, new StringBuilder(), params).toString();
3246        }
3247        /** Returns the command header text as a string. Header text can be zero or more lines, and can be specified
3248         * declaratively with the {@link Command#header()} annotation attribute or programmatically by
3249         * setting the Help instance's {@link Help#header} field.
3250         * @param params Arguments referenced by the format specifiers in the header strings
3251         * @return the header lines combined into a single String (which may be empty)
3252         */
3253        public String header(final Object... params) {
3254            return join(ansi(), header, new StringBuilder(), params).toString();
3255        }
3256        /** Returns command footer text as a string. Footer text can be zero or more lines, and can be specified
3257         * declaratively with the {@link Command#footer()} annotation attribute or programmatically by
3258         * setting the Help instance's {@link Help#footer} field.
3259         * @param params Arguments referenced by the format specifiers in the footer strings
3260         * @return the footer lines combined into a single String (which may be empty)
3261         */
3262        public String footer(final Object... params) {
3263            return join(ansi(), footer, new StringBuilder(), params).toString();
3264        }
3265
3266        /** Returns the text displayed before the header text; the result of {@code String.format(headerHeading, params)}.
3267         * @param params the parameters to use to format the header heading
3268         * @return the formatted header heading */
3269        public String headerHeading(final Object... params) {
3270            return heading(ansi(), headerHeading, params);
3271        }
3272
3273        /** Returns the text displayed before the synopsis text; the result of {@code String.format(synopsisHeading, params)}.
3274         * @param params the parameters to use to format the synopsis heading
3275         * @return the formatted synopsis heading */
3276        public String synopsisHeading(final Object... params) {
3277            return heading(ansi(), synopsisHeading, params);
3278        }
3279
3280        /** Returns the text displayed before the description text; an empty string if there is no description,
3281         * otherwise the result of {@code String.format(descriptionHeading, params)}.
3282         * @param params the parameters to use to format the description heading
3283         * @return the formatted description heading */
3284        public String descriptionHeading(final Object... params) {
3285            return empty(descriptionHeading) ? "" : heading(ansi(), descriptionHeading, params);
3286        }
3287
3288        /** Returns the text displayed before the positional parameter list; an empty string if there are no positional
3289         * parameters, otherwise the result of {@code String.format(parameterListHeading, params)}.
3290         * @param params the parameters to use to format the parameter list heading
3291         * @return the formatted parameter list heading */
3292        public String parameterListHeading(final Object... params) {
3293            return positionalParametersFields.isEmpty() ? "" : heading(ansi(), parameterListHeading, params);
3294        }
3295
3296        /** Returns the text displayed before the option list; an empty string if there are no options,
3297         * otherwise the result of {@code String.format(optionListHeading, params)}.
3298         * @param params the parameters to use to format the option list heading
3299         * @return the formatted option list heading */
3300        public String optionListHeading(final Object... params) {
3301            return optionFields.isEmpty() ? "" : heading(ansi(), optionListHeading, params);
3302        }
3303
3304        /** Returns the text displayed before the command list; an empty string if there are no commands,
3305         * otherwise the result of {@code String.format(commandListHeading, params)}.
3306         * @param params the parameters to use to format the command list heading
3307         * @return the formatted command list heading */
3308        public String commandListHeading(final Object... params) {
3309            return commands.isEmpty() ? "" : heading(ansi(), commandListHeading, params);
3310        }
3311
3312        /** Returns the text displayed before the footer text; the result of {@code String.format(footerHeading, params)}.
3313         * @param params the parameters to use to format the footer heading
3314         * @return the formatted footer heading */
3315        public String footerHeading(final Object... params) {
3316            return heading(ansi(), footerHeading, params);
3317        }
3318        /** Returns a 2-column list with command names and the first line of their header or (if absent) description.
3319         * @return a usage help section describing the added commands */
3320        public String commandList() {
3321            if (commands.isEmpty()) { return ""; }
3322            final int commandLength = maxLength(commands.keySet());
3323            final Help.TextTable textTable = new Help.TextTable(ansi(),
3324                    new Help.Column(commandLength + 2, 2, Help.Column.Overflow.SPAN),
3325                    new Help.Column(usageHelpWidth - (commandLength + 2), 2, Help.Column.Overflow.WRAP));
3326
3327            for (final Map.Entry<String, Help> entry : commands.entrySet()) {
3328                final Help command = entry.getValue();
3329                final String header = command.header != null && command.header.length > 0 ? command.header[0]
3330                        : (command.description != null && command.description.length > 0 ? command.description[0] : "");
3331                textTable.addRowValues(colorScheme.commandText(entry.getKey()), ansi().new Text(header));
3332            }
3333            return textTable.toString();
3334        }
3335        private static int maxLength(final Collection<String> any) {
3336            final List<String> strings = new ArrayList<>(any);
3337            Collections.sort(strings, Collections.reverseOrder(Help.shortestFirst()));
3338            return strings.get(0).length();
3339        }
3340        private static String join(final String[] names, final int offset, final int length, final String separator) {
3341            if (names == null) { return ""; }
3342            final StringBuilder result = new StringBuilder();
3343            for (int i = offset; i < offset + length; i++) {
3344                result.append((i > offset) ? separator : "").append(names[i]);
3345            }
3346            return result.toString();
3347        }
3348        private static String stringOf(final char chr, final int length) {
3349            final char[] buff = new char[length];
3350            Arrays.fill(buff, chr);
3351            return new String(buff);
3352        }
3353
3354        /** Returns a {@code Layout} instance configured with the user preferences captured in this Help instance.
3355         * @return a Layout */
3356        public Layout createDefaultLayout() {
3357            return new Layout(colorScheme, new TextTable(colorScheme.ansi()), createDefaultOptionRenderer(), createDefaultParameterRenderer());
3358        }
3359        /** Returns a new default OptionRenderer which converts {@link Option Options} to five columns of text to match
3360         *  the default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
3361         * <ol>
3362         * <li>the required option marker</li>
3363         * <li>2-character short option name (or empty string if no short option exists)</li>
3364         * <li>comma separator (only if both short option and long option exist, empty string otherwise)</li>
3365         * <li>comma-separated string with long option name(s)</li>
3366         * <li>first element of the {@link Option#description()} array</li>
3367         * </ol>
3368         * <p>Following this, there will be one row for each of the remaining elements of the {@link
3369         *   Option#description()} array, and these rows look like {@code {"", "", "", "", option.description()[i]}}.</p>
3370         * <p>If configured, this option renderer adds an additional row to display the default field value.</p>
3371         * @return a new default OptionRenderer
3372         */
3373        public IOptionRenderer createDefaultOptionRenderer() {
3374            final DefaultOptionRenderer result = new DefaultOptionRenderer();
3375            result.requiredMarker = String.valueOf(requiredOptionMarker);
3376            if (showDefaultValues != null && showDefaultValues.booleanValue()) {
3377                result.command = this.command;
3378            }
3379            return result;
3380        }
3381        /** Returns a new minimal OptionRenderer which converts {@link Option Options} to a single row with two columns
3382         * of text: an option name and a description. If multiple names or descriptions exist, the first value is used.
3383         * @return a new minimal OptionRenderer */
3384        public static IOptionRenderer createMinimalOptionRenderer() {
3385            return new MinimalOptionRenderer();
3386        }
3387
3388        /** Returns a new default ParameterRenderer which converts {@link Parameters Parameters} to four columns of
3389         * text to match the default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
3390         * <ol>
3391         * <li>empty string </li>
3392         * <li>empty string </li>
3393         * <li>parameter(s) label as rendered by the {@link IParamLabelRenderer}</li>
3394         * <li>first element of the {@link Parameters#description()} array</li>
3395         * </ol>
3396         * <p>Following this, there will be one row for each of the remaining elements of the {@link
3397         *   Parameters#description()} array, and these rows look like {@code {"", "", "", param.description()[i]}}.</p>
3398         * <p>If configured, this parameter renderer adds an additional row to display the default field value.</p>
3399         * @return a new default ParameterRenderer
3400         */
3401        public IParameterRenderer createDefaultParameterRenderer() {
3402            final DefaultParameterRenderer result = new DefaultParameterRenderer();
3403            result.requiredMarker = String.valueOf(requiredOptionMarker);
3404            return result;
3405        }
3406        /** Returns a new minimal ParameterRenderer which converts {@link Parameters Parameters} to a single row with
3407         * two columns of text: an option name and a description. If multiple descriptions exist, the first value is used.
3408         * @return a new minimal ParameterRenderer */
3409        public static IParameterRenderer createMinimalParameterRenderer() {
3410            return new MinimalParameterRenderer();
3411        }
3412
3413        /** Returns a value renderer that returns the {@code paramLabel} if defined or the field name otherwise.
3414         * @return a new minimal ParamLabelRenderer */
3415        public static IParamLabelRenderer createMinimalParamLabelRenderer() {
3416            return new IParamLabelRenderer() {
3417                @Override
3418                public Text renderParameterLabel(final Field field, final Ansi ansi, final List<IStyle> styles) {
3419                    final String text = DefaultParamLabelRenderer.renderParameterName(field);
3420                    return ansi.apply(text, styles);
3421                }
3422                @Override
3423                public String separator() { return ""; }
3424            };
3425        }
3426        /** Returns a new default value renderer that separates option parameters from their {@linkplain Option
3427         * options} with the specified separator string, surrounds optional parameters with {@code '['} and {@code ']'}
3428         * characters and uses ellipses ("...") to indicate that any number of a parameter are allowed.
3429         * @return a new default ParamLabelRenderer
3430         */
3431        public IParamLabelRenderer createDefaultParamLabelRenderer() {
3432            return new DefaultParamLabelRenderer(separator);
3433        }
3434        /** Sorts Fields annotated with {@code Option} by their option name in case-insensitive alphabetic order. If an
3435         * Option has multiple names, the shortest name is used for the sorting. Help options follow non-help options.
3436         * @return a comparator that sorts fields by their option name in case-insensitive alphabetic order */
3437        public static Comparator<Field> createShortOptionNameComparator() {
3438            return new SortByShortestOptionNameAlphabetically();
3439        }
3440        /** Sorts Fields annotated with {@code Option} by their option {@linkplain Range#max max arity} first, by
3441         * {@linkplain Range#min min arity} next, and by {@linkplain #createShortOptionNameComparator() option name} last.
3442         * @return a comparator that sorts fields by arity first, then their option name */
3443        public static Comparator<Field> createShortOptionArityAndNameComparator() {
3444            return new SortByOptionArityAndNameAlphabetically();
3445        }
3446        /** Sorts short strings before longer strings.
3447         * @return a comparators that sorts short strings before longer strings */
3448        public static Comparator<String> shortestFirst() {
3449            return new ShortestFirst();
3450        }
3451
3452        /** Returns whether ANSI escape codes are enabled or not.
3453         * @return whether ANSI escape codes are enabled or not
3454         */
3455        public Ansi ansi() {
3456            return colorScheme.ansi;
3457        }
3458
3459        /** When customizing online help for {@link Option Option} details, a custom {@code IOptionRenderer} can be
3460         * used to create textual representation of an Option in a tabular format: one or more rows, each containing
3461         * one or more columns. The {@link Layout Layout} is responsible for placing these text values in the
3462         * {@link TextTable TextTable}. */
3463        public interface IOptionRenderer {
3464            /**
3465             * Returns a text representation of the specified Option and the Field that captures the option value.
3466             * @param option the command line option to show online usage help for
3467             * @param field the field that will hold the value for the command line option
3468             * @param parameterLabelRenderer responsible for rendering option parameters to text
3469             * @param scheme color scheme for applying ansi color styles to options and option parameters
3470             * @return a 2-dimensional array of text values: one or more rows, each containing one or more columns
3471             */
3472            Text[][] render(Option option, Field field, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme);
3473        }
3474        /** The DefaultOptionRenderer converts {@link Option Options} to five columns of text to match the default
3475         * {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
3476         * <ol>
3477         * <li>the required option marker (if the option is required)</li>
3478         * <li>2-character short option name (or empty string if no short option exists)</li>
3479         * <li>comma separator (only if both short option and long option exist, empty string otherwise)</li>
3480         * <li>comma-separated string with long option name(s)</li>
3481         * <li>first element of the {@link Option#description()} array</li>
3482         * </ol>
3483         * <p>Following this, there will be one row for each of the remaining elements of the {@link
3484         *   Option#description()} array, and these rows look like {@code {"", "", "", option.description()[i]}}.</p>
3485         */
3486        static class DefaultOptionRenderer implements IOptionRenderer {
3487            public String requiredMarker = " ";
3488            public Object command;
3489            private String sep;
3490            private boolean showDefault;
3491            @Override
3492            public Text[][] render(final Option option, final Field field, final IParamLabelRenderer paramLabelRenderer, final ColorScheme scheme) {
3493                final String[] names = ShortestFirst.sort(option.names());
3494                final int shortOptionCount = names[0].length() == 2 ? 1 : 0;
3495                final String shortOption = shortOptionCount > 0 ? names[0] : "";
3496                sep = shortOptionCount > 0 && names.length > 1 ? "," : "";
3497
3498                final String longOption = join(names, shortOptionCount, names.length - shortOptionCount, ", ");
3499                final Text longOptionText = createLongOptionText(field, paramLabelRenderer, scheme, longOption);
3500
3501                showDefault = command != null && !option.help() && !isBoolean(field.getType());
3502                final Object defaultValue = createDefaultValue(field);
3503
3504                final String requiredOption = option.required() ? requiredMarker : "";
3505                return renderDescriptionLines(option, scheme, requiredOption, shortOption, longOptionText, defaultValue);
3506            }
3507
3508            private Object createDefaultValue(final Field field) {
3509                Object defaultValue = null;
3510                try {
3511                    defaultValue = field.get(command);
3512                    if (defaultValue == null) { showDefault = false; } // #201 don't show null default values
3513                    else if (field.getType().isArray()) {
3514                        final StringBuilder sb = new StringBuilder();
3515                        for (int i = 0; i < Array.getLength(defaultValue); i++) {
3516                            sb.append(i > 0 ? ", " : "").append(Array.get(defaultValue, i));
3517                        }
3518                        defaultValue = sb.insert(0, "[").append("]").toString();
3519                    }
3520                } catch (final Exception ex) {
3521                    showDefault = false;
3522                }
3523                return defaultValue;
3524            }
3525
3526            private Text createLongOptionText(final Field field, final IParamLabelRenderer renderer, final ColorScheme scheme, final String longOption) {
3527                Text paramLabelText = renderer.renderParameterLabel(field, scheme.ansi(), scheme.optionParamStyles);
3528
3529                // if no long option, fill in the space between the short option name and the param label value
3530                if (paramLabelText.length > 0 && longOption.length() == 0) {
3531                    sep = renderer.separator();
3532                    // #181 paramLabelText may be =LABEL or [=LABEL...]
3533                    final int sepStart = paramLabelText.plainString().indexOf(sep);
3534                    final Text prefix = paramLabelText.substring(0, sepStart);
3535                    paramLabelText = prefix.append(paramLabelText.substring(sepStart + sep.length()));
3536                }
3537                Text longOptionText = scheme.optionText(longOption);
3538                longOptionText = longOptionText.append(paramLabelText);
3539                return longOptionText;
3540            }
3541
3542            private Text[][] renderDescriptionLines(final Option option,
3543                                                    final ColorScheme scheme,
3544                                                    final String requiredOption,
3545                                                    final String shortOption,
3546                                                    final Text longOptionText,
3547                                                    final Object defaultValue) {
3548                final Text EMPTY = Ansi.EMPTY_TEXT;
3549                final List<Text[]> result = new ArrayList<>();
3550                Text[] descriptionFirstLines = scheme.ansi().new Text(str(option.description(), 0)).splitLines();
3551                if (descriptionFirstLines.length == 0) {
3552                    if (showDefault) {
3553                        descriptionFirstLines = new Text[]{scheme.ansi().new Text("  Default: " + defaultValue)};
3554                        showDefault = false; // don't show the default value twice
3555                    } else {
3556                        descriptionFirstLines = new Text[]{ EMPTY };
3557                    }
3558                }
3559                result.add(new Text[] { scheme.optionText(requiredOption), scheme.optionText(shortOption),
3560                        scheme.ansi().new Text(sep), longOptionText, descriptionFirstLines[0] });
3561                for (int i = 1; i < descriptionFirstLines.length; i++) {
3562                    result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, descriptionFirstLines[i] });
3563                }
3564                for (int i = 1; i < option.description().length; i++) {
3565                    final Text[] descriptionNextLines = scheme.ansi().new Text(option.description()[i]).splitLines();
3566                    for (final Text line : descriptionNextLines) {
3567                        result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, line });
3568                    }
3569                }
3570                if (showDefault) {
3571                    result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, scheme.ansi().new Text("  Default: " + defaultValue) });
3572                }
3573                return result.toArray(new Text[result.size()][]);
3574            }
3575        }
3576        /** The MinimalOptionRenderer converts {@link Option Options} to a single row with two columns of text: an
3577         * option name and a description. If multiple names or description lines exist, the first value is used. */
3578        static class MinimalOptionRenderer implements IOptionRenderer {
3579            @Override
3580            public Text[][] render(final Option option, final Field field, final IParamLabelRenderer parameterLabelRenderer, final ColorScheme scheme) {
3581                Text optionText = scheme.optionText(option.names()[0]);
3582                final Text paramLabelText = parameterLabelRenderer.renderParameterLabel(field, scheme.ansi(), scheme.optionParamStyles);
3583                optionText = optionText.append(paramLabelText);
3584                return new Text[][] {{ optionText,
3585                                        scheme.ansi().new Text(option.description().length == 0 ? "" : option.description()[0]) }};
3586            }
3587        }
3588        /** The MinimalParameterRenderer converts {@link Parameters Parameters} to a single row with two columns of
3589         * text: the parameters label and a description. If multiple description lines exist, the first value is used. */
3590        static class MinimalParameterRenderer implements IParameterRenderer {
3591            @Override
3592            public Text[][] render(final Parameters param, final Field field, final IParamLabelRenderer parameterLabelRenderer, final ColorScheme scheme) {
3593                return new Text[][] {{ parameterLabelRenderer.renderParameterLabel(field, scheme.ansi(), scheme.parameterStyles),
3594                        scheme.ansi().new Text(param.description().length == 0 ? "" : param.description()[0]) }};
3595            }
3596        }
3597        /** When customizing online help for {@link Parameters Parameters} details, a custom {@code IParameterRenderer}
3598         * can be used to create textual representation of a Parameters field in a tabular format: one or more rows,
3599         * each containing one or more columns. The {@link Layout Layout} is responsible for placing these text
3600         * values in the {@link TextTable TextTable}. */
3601        public interface IParameterRenderer {
3602            /**
3603             * Returns a text representation of the specified Parameters and the Field that captures the parameter values.
3604             * @param parameters the command line parameters to show online usage help for
3605             * @param field the field that will hold the value for the command line parameters
3606             * @param parameterLabelRenderer responsible for rendering parameter labels to text
3607             * @param scheme color scheme for applying ansi color styles to positional parameters
3608             * @return a 2-dimensional array of text values: one or more rows, each containing one or more columns
3609             */
3610            Text[][] render(Parameters parameters, Field field, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme);
3611        }
3612        /** The DefaultParameterRenderer converts {@link Parameters Parameters} to five columns of text to match the
3613         * default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
3614         * <ol>
3615         * <li>the required option marker (if the parameter's arity is to have at least one value)</li>
3616         * <li>empty string </li>
3617         * <li>empty string </li>
3618         * <li>parameter(s) label as rendered by the {@link IParamLabelRenderer}</li>
3619         * <li>first element of the {@link Parameters#description()} array</li>
3620         * </ol>
3621         * <p>Following this, there will be one row for each of the remaining elements of the {@link
3622         *   Parameters#description()} array, and these rows look like {@code {"", "", "", param.description()[i]}}.</p>
3623         */
3624        static class DefaultParameterRenderer implements IParameterRenderer {
3625            public String requiredMarker = " ";
3626            @Override
3627            public Text[][] render(final Parameters params, final Field field, final IParamLabelRenderer paramLabelRenderer, final ColorScheme scheme) {
3628                final Text label = paramLabelRenderer.renderParameterLabel(field, scheme.ansi(), scheme.parameterStyles);
3629                final Text requiredParameter = scheme.parameterText(Range.parameterArity(field).min > 0 ? requiredMarker : "");
3630
3631                final Text EMPTY = Ansi.EMPTY_TEXT;
3632                final List<Text[]> result = new ArrayList<>();
3633                Text[] descriptionFirstLines = scheme.ansi().new Text(str(params.description(), 0)).splitLines();
3634                if (descriptionFirstLines.length == 0) { descriptionFirstLines = new Text[]{ EMPTY }; }
3635                result.add(new Text[] { requiredParameter, EMPTY, EMPTY, label, descriptionFirstLines[0] });
3636                for (int i = 1; i < descriptionFirstLines.length; i++) {
3637                    result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, descriptionFirstLines[i] });
3638                }
3639                for (int i = 1; i < params.description().length; i++) {
3640                    final Text[] descriptionNextLines = scheme.ansi().new Text(params.description()[i]).splitLines();
3641                    for (final Text line : descriptionNextLines) {
3642                        result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, line });
3643                    }
3644                }
3645                return result.toArray(new Text[result.size()][]);
3646            }
3647        }
3648        /** When customizing online usage help for an option parameter or a positional parameter, a custom
3649         * {@code IParamLabelRenderer} can be used to render the parameter name or label to a String. */
3650        public interface IParamLabelRenderer {
3651
3652            /** Returns a text rendering of the Option parameter or positional parameter; returns an empty string
3653             * {@code ""} if the option is a boolean and does not take a parameter.
3654             * @param field the annotated field with a parameter label
3655             * @param ansi determines whether ANSI escape codes should be emitted or not
3656             * @param styles the styles to apply to the parameter label
3657             * @return a text rendering of the Option parameter or positional parameter */
3658            Text renderParameterLabel(Field field, Ansi ansi, List<IStyle> styles);
3659
3660            /** Returns the separator between option name and param label.
3661             * @return the separator between option name and param label */
3662            String separator();
3663        }
3664        /**
3665         * DefaultParamLabelRenderer separates option parameters from their {@linkplain Option options} with a
3666         * {@linkplain DefaultParamLabelRenderer#separator separator} string, surrounds optional values
3667         * with {@code '['} and {@code ']'} characters and uses ellipses ("...") to indicate that any number of
3668         * values is allowed for options or parameters with variable arity.
3669         */
3670        static class DefaultParamLabelRenderer implements IParamLabelRenderer {
3671            /** The string to use to separate option parameters from their options. */
3672            public final String separator;
3673            /** Constructs a new DefaultParamLabelRenderer with the specified separator string. */
3674            public DefaultParamLabelRenderer(final String separator) {
3675                this.separator = Assert.notNull(separator, "separator");
3676            }
3677            @Override
3678            public String separator() { return separator; }
3679            @Override
3680            public Text renderParameterLabel(final Field field, final Ansi ansi, final List<IStyle> styles) {
3681                final boolean isOptionParameter = field.isAnnotationPresent(Option.class);
3682                final Range arity = isOptionParameter ? Range.optionArity(field) : Range.parameterCapacity(field);
3683                final String split = isOptionParameter ? field.getAnnotation(Option.class).split() : field.getAnnotation(Parameters.class).split();
3684                Text result = ansi.new Text("");
3685                String sep = isOptionParameter ? separator : "";
3686                Text paramName = ansi.apply(renderParameterName(field), styles);
3687                if (!empty(split)) { paramName = paramName.append("[" + split).append(paramName).append("]..."); } // #194
3688                for (int i = 0; i < arity.min; i++) {
3689                    result = result.append(sep).append(paramName);
3690                    sep = " ";
3691                }
3692                if (arity.isVariable) {
3693                    if (result.length == 0) { // arity="*" or arity="0..*"
3694                        result = result.append(sep + "[").append(paramName).append("]...");
3695                    } else if (!result.plainString().endsWith("...")) { // split param may already end with "..."
3696                        result = result.append("...");
3697                    }
3698                } else {
3699                    sep = result.length == 0 ? (isOptionParameter ? separator : "") : " ";
3700                    for (int i = arity.min; i < arity.max; i++) {
3701                        if (sep.trim().length() == 0) {
3702                            result = result.append(sep + "[").append(paramName);
3703                        } else {
3704                            result = result.append("[" + sep).append(paramName);
3705                        }
3706                        sep  = " ";
3707                    }
3708                    for (int i = arity.min; i < arity.max; i++) { result = result.append("]"); }
3709                }
3710                return result;
3711            }
3712            private static String renderParameterName(final Field field) {
3713                String result = null;
3714                if (field.isAnnotationPresent(Option.class)) {
3715                    result = field.getAnnotation(Option.class).paramLabel();
3716                } else if (field.isAnnotationPresent(Parameters.class)) {
3717                    result = field.getAnnotation(Parameters.class).paramLabel();
3718                }
3719                if (result != null && result.trim().length() > 0) {
3720                    return result.trim();
3721                }
3722                String name = field.getName();
3723                if (Map.class.isAssignableFrom(field.getType())) { // #195 better param labels for map fields
3724                    final Class<?>[] paramTypes = getTypeAttribute(field);
3725                    if (paramTypes.length < 2 || paramTypes[0] == null || paramTypes[1] == null) {
3726                        name = "String=String";
3727                    } else { name = paramTypes[0].getSimpleName() + "=" + paramTypes[1].getSimpleName(); }
3728                }
3729                return "<" + name + ">";
3730            }
3731        }
3732        /** Use a Layout to format usage help text for options and parameters in tabular format.
3733         * <p>Delegates to the renderers to create {@link Text} values for the annotated fields, and uses a
3734         * {@link TextTable} to display these values in tabular format. Layout is responsible for deciding which values
3735         * to display where in the table. By default, Layout shows one option or parameter per table row.</p>
3736         * <p>Customize by overriding the {@link #layout(Field, CommandLine.Help.Ansi.Text[][])} method.</p>
3737         * @see IOptionRenderer rendering options to text
3738         * @see IParameterRenderer rendering parameters to text
3739         * @see TextTable showing values in a tabular format
3740         */
3741        public static class Layout {
3742            protected final ColorScheme colorScheme;
3743            protected final TextTable table;
3744            protected IOptionRenderer optionRenderer;
3745            protected IParameterRenderer parameterRenderer;
3746
3747            /** Constructs a Layout with the specified color scheme, a new default TextTable, the
3748             * {@linkplain Help#createDefaultOptionRenderer() default option renderer}, and the
3749             * {@linkplain Help#createDefaultParameterRenderer() default parameter renderer}.
3750             * @param colorScheme the color scheme to use for common, auto-generated parts of the usage help message */
3751            public Layout(final ColorScheme colorScheme) { this(colorScheme, new TextTable(colorScheme.ansi())); }
3752
3753            /** Constructs a Layout with the specified color scheme, the specified TextTable, the
3754             * {@linkplain Help#createDefaultOptionRenderer() default option renderer}, and the
3755             * {@linkplain Help#createDefaultParameterRenderer() default parameter renderer}.
3756             * @param colorScheme the color scheme to use for common, auto-generated parts of the usage help message
3757             * @param textTable the TextTable to lay out parts of the usage help message in tabular format */
3758            public Layout(final ColorScheme colorScheme, final TextTable textTable) {
3759                this(colorScheme, textTable, new DefaultOptionRenderer(), new DefaultParameterRenderer());
3760            }
3761            /** Constructs a Layout with the specified color scheme, the specified TextTable, the
3762             * specified option renderer and the specified parameter renderer.
3763             * @param colorScheme the color scheme to use for common, auto-generated parts of the usage help message
3764             * @param optionRenderer the object responsible for rendering Options to Text
3765             * @param parameterRenderer the object responsible for rendering Parameters to Text
3766             * @param textTable the TextTable to lay out parts of the usage help message in tabular format */
3767            public Layout(final ColorScheme colorScheme, final TextTable textTable, final IOptionRenderer optionRenderer, final IParameterRenderer parameterRenderer) {
3768                this.colorScheme       = Assert.notNull(colorScheme, "colorScheme");
3769                this.table             = Assert.notNull(textTable, "textTable");
3770                this.optionRenderer    = Assert.notNull(optionRenderer, "optionRenderer");
3771                this.parameterRenderer = Assert.notNull(parameterRenderer, "parameterRenderer");
3772            }
3773            /**
3774             * Copies the specified text values into the correct cells in the {@link TextTable}. This implementation
3775             * delegates to {@link TextTable#addRowValues(CommandLine.Help.Ansi.Text...)} for each row of values.
3776             * <p>Subclasses may override.</p>
3777             * @param field the field annotated with the specified Option or Parameters
3778             * @param cellValues the text values representing the Option/Parameters, to be displayed in tabular form
3779             */
3780            public void layout(final Field field, final Text[][] cellValues) {
3781                for (final Text[] oneRow : cellValues) {
3782                    table.addRowValues(oneRow);
3783                }
3784            }
3785            /** Calls {@link #addOption(Field, CommandLine.Help.IParamLabelRenderer)} for all non-hidden Options in the list.
3786             * @param fields fields annotated with {@link Option} to add usage descriptions for
3787             * @param paramLabelRenderer object that knows how to render option parameters */
3788            public void addOptions(final List<Field> fields, final IParamLabelRenderer paramLabelRenderer) {
3789                for (final Field field : fields) {
3790                    final Option option = field.getAnnotation(Option.class);
3791                    if (!option.hidden()) {
3792                        addOption(field, paramLabelRenderer);
3793                    }
3794                }
3795            }
3796            /**
3797             * Delegates to the {@link #optionRenderer option renderer} of this layout to obtain
3798             * text values for the specified {@link Option}, and then calls the {@link #layout(Field, CommandLine.Help.Ansi.Text[][])}
3799             * method to write these text values into the correct cells in the TextTable.
3800             * @param field the field annotated with the specified Option
3801             * @param paramLabelRenderer knows how to render option parameters
3802             */
3803            public void addOption(final Field field, final IParamLabelRenderer paramLabelRenderer) {
3804                final Option option = field.getAnnotation(Option.class);
3805                final Text[][] values = optionRenderer.render(option, field, paramLabelRenderer, colorScheme);
3806                layout(field, values);
3807            }
3808            /** Calls {@link #addPositionalParameter(Field, CommandLine.Help.IParamLabelRenderer)} for all non-hidden Parameters in the list.
3809             * @param fields fields annotated with {@link Parameters} to add usage descriptions for
3810             * @param paramLabelRenderer knows how to render option parameters */
3811            public void addPositionalParameters(final List<Field> fields, final IParamLabelRenderer paramLabelRenderer) {
3812                for (final Field field : fields) {
3813                    final Parameters parameters = field.getAnnotation(Parameters.class);
3814                    if (!parameters.hidden()) {
3815                        addPositionalParameter(field, paramLabelRenderer);
3816                    }
3817                }
3818            }
3819            /**
3820             * Delegates to the {@link #parameterRenderer parameter renderer} of this layout
3821             * to obtain text values for the specified {@link Parameters}, and then calls
3822             * {@link #layout(Field, CommandLine.Help.Ansi.Text[][])} to write these text values into the correct cells in the TextTable.
3823             * @param field the field annotated with the specified Parameters
3824             * @param paramLabelRenderer knows how to render option parameters
3825             */
3826            public void addPositionalParameter(final Field field, final IParamLabelRenderer paramLabelRenderer) {
3827                final Parameters option = field.getAnnotation(Parameters.class);
3828                final Text[][] values = parameterRenderer.render(option, field, paramLabelRenderer, colorScheme);
3829                layout(field, values);
3830            }
3831            /** Returns the section of the usage help message accumulated in the TextTable owned by this layout. */
3832            @Override public String toString() {
3833                return table.toString();
3834            }
3835        }
3836        /** Sorts short strings before longer strings. */
3837        static class ShortestFirst implements Comparator<String> {
3838            @Override
3839            public int compare(final String o1, final String o2) {
3840                return o1.length() - o2.length();
3841            }
3842            /** Sorts the specified array of Strings shortest-first and returns it. */
3843            public static String[] sort(final String[] names) {
3844                Arrays.sort(names, new ShortestFirst());
3845                return names;
3846            }
3847        }
3848        /** Sorts {@code Option} instances by their name in case-insensitive alphabetic order. If an Option has
3849         * multiple names, the shortest name is used for the sorting. Help options follow non-help options. */
3850        static class SortByShortestOptionNameAlphabetically implements Comparator<Field> {
3851            @Override
3852            public int compare(final Field f1, final Field f2) {
3853                final Option o1 = f1.getAnnotation(Option.class);
3854                final Option o2 = f2.getAnnotation(Option.class);
3855                if (o1 == null) { return 1; } else if (o2 == null) { return -1; } // options before params
3856                final String[] names1 = ShortestFirst.sort(o1.names());
3857                final String[] names2 = ShortestFirst.sort(o2.names());
3858                int result = names1[0].toUpperCase().compareTo(names2[0].toUpperCase()); // case insensitive sort
3859                result = result == 0 ? -names1[0].compareTo(names2[0]) : result; // lower case before upper case
3860                return o1.help() == o2.help() ? result : o2.help() ? -1 : 1; // help options come last
3861            }
3862        }
3863        /** Sorts {@code Option} instances by their max arity first, then their min arity, then delegates to super class. */
3864        static class SortByOptionArityAndNameAlphabetically extends SortByShortestOptionNameAlphabetically {
3865            @Override
3866            public int compare(final Field f1, final Field f2) {
3867                final Option o1 = f1.getAnnotation(Option.class);
3868                final Option o2 = f2.getAnnotation(Option.class);
3869                final Range arity1 = Range.optionArity(f1);
3870                final Range arity2 = Range.optionArity(f2);
3871                int result = arity1.max - arity2.max;
3872                if (result == 0) {
3873                    result = arity1.min - arity2.min;
3874                }
3875                if (result == 0) { // arity is same
3876                    if (isMultiValue(f1) && !isMultiValue(f2)) { result = 1; } // f1 > f2
3877                    if (!isMultiValue(f1) && isMultiValue(f2)) { result = -1; } // f1 < f2
3878                }
3879                return result == 0 ? super.compare(f1, f2) : result;
3880            }
3881        }
3882        /**
3883         * <p>Responsible for spacing out {@link Text} values according to the {@link Column} definitions the table was
3884         * created with. Columns have a width, indentation, and an overflow policy that decides what to do if a value is
3885         * longer than the column's width.</p>
3886         */
3887        public static class TextTable {
3888            /**
3889             * Helper class to index positions in a {@code Help.TextTable}.
3890             * @since 2.0
3891             */
3892            public static class Cell {
3893                /** Table column index (zero based). */
3894                public final int column;
3895                /** Table row index (zero based). */
3896                public final int row;
3897                /** Constructs a new Cell with the specified coordinates in the table.
3898                 * @param column the zero-based table column
3899                 * @param row the zero-based table row */
3900                public Cell(final int column, final int row) { this.column = column; this.row = row; }
3901            }
3902
3903            /** The column definitions of this table. */
3904            public final Column[] columns;
3905
3906            /** The {@code char[]} slots of the {@code TextTable} to copy text values into. */
3907            protected final List<Text> columnValues = new ArrayList<>();
3908
3909            /** By default, indent wrapped lines by 2 spaces. */
3910            public int indentWrappedLines = 2;
3911
3912            private final Ansi ansi;
3913
3914            /** Constructs a TextTable with five columns as follows:
3915             * <ol>
3916             * <li>required option/parameter marker (width: 2, indent: 0, TRUNCATE on overflow)</li>
3917             * <li>short option name (width: 2, indent: 0, TRUNCATE on overflow)</li>
3918             * <li>comma separator (width: 1, indent: 0, TRUNCATE on overflow)</li>
3919             * <li>long option name(s) (width: 24, indent: 1, SPAN multiple columns on overflow)</li>
3920             * <li>description line(s) (width: 51, indent: 1, WRAP to next row on overflow)</li>
3921             * </ol>
3922             * @param ansi whether to emit ANSI escape codes or not
3923             */
3924            public TextTable(final Ansi ansi) {
3925                // "* -c, --create                Creates a ...."
3926                this(ansi, new Column[] {
3927                            new Column(2,                                        0, TRUNCATE), // "*"
3928                            new Column(2,                                        0, TRUNCATE), // "-c"
3929                            new Column(1,                                        0, TRUNCATE), // ","
3930                            new Column(optionsColumnWidth - 2 - 2 - 1       , 1, SPAN),  // " --create"
3931                            new Column(usageHelpWidth - optionsColumnWidth, 1, WRAP) // " Creates a ..."
3932                    });
3933            }
3934
3935            /** Constructs a new TextTable with columns with the specified width, all SPANning  multiple columns on
3936             * overflow except the last column which WRAPS to the next row.
3937             * @param ansi whether to emit ANSI escape codes or not
3938             * @param columnWidths the width of the table columns (all columns have zero indent)
3939             */
3940            public TextTable(final Ansi ansi, final int... columnWidths) {
3941                this.ansi = Assert.notNull(ansi, "ansi");
3942                columns = new Column[columnWidths.length];
3943                for (int i = 0; i < columnWidths.length; i++) {
3944                    columns[i] = new Column(columnWidths[i], 0, i == columnWidths.length - 1 ? SPAN: WRAP);
3945                }
3946            }
3947            /** Constructs a {@code TextTable} with the specified columns.
3948             * @param ansi whether to emit ANSI escape codes or not
3949             * @param columns columns to construct this TextTable with */
3950            public TextTable(final Ansi ansi, final Column... columns) {
3951                this.ansi = Assert.notNull(ansi, "ansi");
3952                this.columns = Assert.notNull(columns, "columns");
3953                if (columns.length == 0) { throw new IllegalArgumentException("At least one column is required"); }
3954            }
3955            /** Returns the {@code Text} slot at the specified row and column to write a text value into.
3956             * @param row the row of the cell whose Text to return
3957             * @param col the column of the cell whose Text to return
3958             * @return the Text object at the specified row and column
3959             * @since 2.0 */
3960            public Text textAt(final int row, final int col) { return columnValues.get(col + (row * columns.length)); }
3961
3962            /** Returns the {@code Text} slot at the specified row and column to write a text value into.
3963             * @param row the row of the cell whose Text to return
3964             * @param col the column of the cell whose Text to return
3965             * @return the Text object at the specified row and column
3966             * @deprecated use {@link #textAt(int, int)} instead */
3967            @Deprecated
3968            public Text cellAt(final int row, final int col) { return textAt(row, col); }
3969
3970            /** Returns the current number of rows of this {@code TextTable}.
3971             * @return the current number of rows in this TextTable */
3972            public int rowCount() { return columnValues.size() / columns.length; }
3973
3974            /** Adds the required {@code char[]} slots for a new row to the {@link #columnValues} field. */
3975            public void addEmptyRow() {
3976                for (int i = 0; i < columns.length; i++) {
3977                    columnValues.add(ansi.new Text(columns[i].width));
3978                }
3979            }
3980
3981            /** Delegates to {@link #addRowValues(CommandLine.Help.Ansi.Text...)}.
3982             * @param values the text values to display in each column of the current row */
3983            public void addRowValues(final String... values) {
3984                final Text[] array = new Text[values.length];
3985                for (int i = 0; i < array.length; i++) {
3986                    array[i] = values[i] == null ? Ansi.EMPTY_TEXT : ansi.new Text(values[i]);
3987                }
3988                addRowValues(array);
3989            }
3990            /**
3991             * Adds a new {@linkplain TextTable#addEmptyRow() empty row}, then calls {@link
3992             * TextTable#putValue(int, int, CommandLine.Help.Ansi.Text) putValue} for each of the specified values, adding more empty rows
3993             * if the return value indicates that the value spanned multiple columns or was wrapped to multiple rows.
3994             * @param values the values to write into a new row in this TextTable
3995             * @throws IllegalArgumentException if the number of values exceeds the number of Columns in this table
3996             */
3997            public void addRowValues(final Text... values) {
3998                if (values.length > columns.length) {
3999                    throw new IllegalArgumentException(values.length + " values don't fit in " +
4000                            columns.length + " columns");
4001                }
4002                addEmptyRow();
4003                for (int col = 0; col < values.length; col++) {
4004                    final int row = rowCount() - 1;// write to last row: previous value may have wrapped to next row
4005                    final Cell cell = putValue(row, col, values[col]);
4006
4007                    // add row if a value spanned/wrapped and there are still remaining values
4008                    if ((cell.row != row || cell.column != col) && col != values.length - 1) {
4009                        addEmptyRow();
4010                    }
4011                }
4012            }
4013            /**
4014             * Writes the specified value into the cell at the specified row and column and returns the last row and
4015             * column written to. Depending on the Column's {@link Column#overflow Overflow} policy, the value may span
4016             * multiple columns or wrap to multiple rows when larger than the column width.
4017             * @param row the target row in the table
4018             * @param col the target column in the table to write to
4019             * @param value the value to write
4020             * @return a Cell indicating the position in the table that was last written to (since 2.0)
4021             * @throws IllegalArgumentException if the specified row exceeds the table's {@linkplain
4022             *          TextTable#rowCount() row count}
4023             * @since 2.0 (previous versions returned a {@code java.awt.Point} object)
4024             */
4025            public Cell putValue(int row, int col, Text value) {
4026                if (row > rowCount() - 1) {
4027                    throw new IllegalArgumentException("Cannot write to row " + row + ": rowCount=" + rowCount());
4028                }
4029                if (value == null || value.plain.length() == 0) { return new Cell(col, row); }
4030                final Column column = columns[col];
4031                int indent = column.indent;
4032                switch (column.overflow) {
4033                    case TRUNCATE:
4034                        copy(value, textAt(row, col), indent);
4035                        return new Cell(col, row);
4036                    case SPAN:
4037                        final int startColumn = col;
4038                        do {
4039                            final boolean lastColumn = col == columns.length - 1;
4040                            final int charsWritten = lastColumn
4041                                    ? copy(BreakIterator.getLineInstance(), value, textAt(row, col), indent)
4042                                    : copy(value, textAt(row, col), indent);
4043                            value = value.substring(charsWritten);
4044                            indent = 0;
4045                            if (value.length > 0) { // value did not fit in column
4046                                ++col;                // write remainder of value in next column
4047                            }
4048                            if (value.length > 0 && col >= columns.length) { // we filled up all columns on this row
4049                                addEmptyRow();
4050                                row++;
4051                                col = startColumn;
4052                                indent = column.indent + indentWrappedLines;
4053                            }
4054                        } while (value.length > 0);
4055                        return new Cell(col, row);
4056                    case WRAP:
4057                        final BreakIterator lineBreakIterator = BreakIterator.getLineInstance();
4058                        do {
4059                            final int charsWritten = copy(lineBreakIterator, value, textAt(row, col), indent);
4060                            value = value.substring(charsWritten);
4061                            indent = column.indent + indentWrappedLines;
4062                            if (value.length > 0) {  // value did not fit in column
4063                                ++row;                 // write remainder of value in next row
4064                                addEmptyRow();
4065                            }
4066                        } while (value.length > 0);
4067                        return new Cell(col, row);
4068                }
4069                throw new IllegalStateException(column.overflow.toString());
4070            }
4071            private static int length(final Text str) {
4072                return str.length; // TODO count some characters as double length
4073            }
4074
4075            private int copy(final BreakIterator line, final Text text, final Text columnValue, final int offset) {
4076                // Deceive the BreakIterator to ensure no line breaks after '-' character
4077                line.setText(text.plainString().replace("-", "\u00ff"));
4078                int done = 0;
4079                for (int start = line.first(), end = line.next(); end != BreakIterator.DONE; start = end, end = line.next()) {
4080                    final Text word = text.substring(start, end); //.replace("\u00ff", "-"); // not needed
4081                    if (columnValue.maxLength >= offset + done + length(word)) {
4082                        done += copy(word, columnValue, offset + done); // TODO localized length
4083                    } else {
4084                        break;
4085                    }
4086                }
4087                if (done == 0 && length(text) > columnValue.maxLength) {
4088                    // The value is a single word that is too big to be written to the column. Write as much as we can.
4089                    done = copy(text, columnValue, offset);
4090                }
4091                return done;
4092            }
4093            private static int copy(final Text value, final Text destination, final int offset) {
4094                final int length = Math.min(value.length, destination.maxLength - offset);
4095                value.getStyledChars(value.from, length, destination, offset);
4096                return length;
4097            }
4098
4099            /** Copies the text representation that we built up from the options into the specified StringBuilder.
4100             * @param text the StringBuilder to write into
4101             * @return the specified StringBuilder object (to allow method chaining and a more fluid API) */
4102            public StringBuilder toString(final StringBuilder text) {
4103                final int columnCount = this.columns.length;
4104                final StringBuilder row = new StringBuilder(usageHelpWidth);
4105                for (int i = 0; i < columnValues.size(); i++) {
4106                    final Text column = columnValues.get(i);
4107                    row.append(column.toString());
4108                    row.append(new String(spaces(columns[i % columnCount].width - column.length)));
4109                    if (i % columnCount == columnCount - 1) {
4110                        int lastChar = row.length() - 1;
4111                        while (lastChar >= 0 && row.charAt(lastChar) == ' ') {lastChar--;} // rtrim
4112                        row.setLength(lastChar + 1);
4113                        text.append(row.toString()).append(System.getProperty("line.separator"));
4114                        row.setLength(0);
4115                    }
4116                }
4117                //if (Ansi.enabled()) { text.append(Style.reset.off()); }
4118                return text;
4119            }
4120            @Override
4121            public String toString() { return toString(new StringBuilder()).toString(); }
4122        }
4123        /** Columns define the width, indent (leading number of spaces in a column before the value) and
4124         * {@linkplain Overflow Overflow} policy of a column in a {@linkplain TextTable TextTable}. */
4125        public static class Column {
4126
4127            /** Policy for handling text that is longer than the column width:
4128             *  span multiple columns, wrap to the next row, or simply truncate the portion that doesn't fit. */
4129            public enum Overflow { TRUNCATE, SPAN, WRAP }
4130
4131            /** Column width in characters */
4132            public final int width;
4133
4134            /** Indent (number of empty spaces at the start of the column preceding the text value) */
4135            public final int indent;
4136
4137            /** Policy that determines how to handle values larger than the column width. */
4138            public final Overflow overflow;
4139            public Column(final int width, final int indent, final Overflow overflow) {
4140                this.width = width;
4141                this.indent = indent;
4142                this.overflow = Assert.notNull(overflow, "overflow");
4143            }
4144        }
4145
4146        /** All usage help message are generated with a color scheme that assigns certain styles and colors to common
4147         * parts of a usage message: the command name, options, positional parameters and option parameters.
4148         * Users may customize these styles by creating Help with a custom color scheme.
4149         * <p>Note that these options and styles may not be rendered if ANSI escape codes are not
4150         * {@linkplain Ansi#enabled() enabled}.</p>
4151         * @see Help#defaultColorScheme(Ansi)
4152         */
4153        public static class ColorScheme {
4154            public final List<IStyle> commandStyles = new ArrayList<>();
4155            public final List<IStyle> optionStyles = new ArrayList<>();
4156            public final List<IStyle> parameterStyles = new ArrayList<>();
4157            public final List<IStyle> optionParamStyles = new ArrayList<>();
4158            private final Ansi ansi;
4159
4160            /** Constructs a new ColorScheme with {@link Help.Ansi#AUTO}. */
4161            public ColorScheme() { this(Ansi.AUTO); }
4162
4163            /** Constructs a new ColorScheme with the specified Ansi enabled mode.
4164             * @param ansi whether to emit ANSI escape codes or not
4165             */
4166            public ColorScheme(final Ansi ansi) {this.ansi = Assert.notNull(ansi, "ansi"); }
4167
4168            /** Adds the specified styles to the registered styles for commands in this color scheme and returns this color scheme.
4169             * @param styles the styles to add to the registered styles for commands in this color scheme
4170             * @return this color scheme to enable method chaining for a more fluent API */
4171            public ColorScheme commands(final IStyle... styles)     { return addAll(commandStyles, styles); }
4172            /** Adds the specified styles to the registered styles for options in this color scheme and returns this color scheme.
4173             * @param styles the styles to add to registered the styles for options in this color scheme
4174             * @return this color scheme to enable method chaining for a more fluent API */
4175            public ColorScheme options(final IStyle... styles)      { return addAll(optionStyles, styles);}
4176            /** Adds the specified styles to the registered styles for positional parameters in this color scheme and returns this color scheme.
4177             * @param styles the styles to add to registered the styles for parameters in this color scheme
4178             * @return this color scheme to enable method chaining for a more fluent API */
4179            public ColorScheme parameters(final IStyle... styles)   { return addAll(parameterStyles, styles);}
4180            /** Adds the specified styles to the registered styles for option parameters in this color scheme and returns this color scheme.
4181             * @param styles the styles to add to the registered styles for option parameters in this color scheme
4182             * @return this color scheme to enable method chaining for a more fluent API */
4183            public ColorScheme optionParams(final IStyle... styles) { return addAll(optionParamStyles, styles);}
4184            /** Returns a Text with all command styles applied to the specified command string.
4185             * @param command the command string to apply the registered command styles to
4186             * @return a Text with all command styles applied to the specified command string */
4187            public Ansi.Text commandText(final String command)         { return ansi().apply(command,     commandStyles); }
4188            /** Returns a Text with all option styles applied to the specified option string.
4189             * @param option the option string to apply the registered option styles to
4190             * @return a Text with all option styles applied to the specified option string */
4191            public Ansi.Text optionText(final String option)           { return ansi().apply(option,      optionStyles); }
4192            /** Returns a Text with all parameter styles applied to the specified parameter string.
4193             * @param parameter the parameter string to apply the registered parameter styles to
4194             * @return a Text with all parameter styles applied to the specified parameter string */
4195            public Ansi.Text parameterText(final String parameter)     { return ansi().apply(parameter,   parameterStyles); }
4196            /** Returns a Text with all optionParam styles applied to the specified optionParam string.
4197             * @param optionParam the option parameter string to apply the registered option parameter styles to
4198             * @return a Text with all option parameter styles applied to the specified option parameter string */
4199            public Ansi.Text optionParamText(final String optionParam) { return ansi().apply(optionParam, optionParamStyles); }
4200
4201            /** Replaces colors and styles in this scheme with ones specified in system properties, and returns this scheme.
4202             * Supported property names:<ul>
4203             *     <li>{@code picocli.color.commands}</li>
4204             *     <li>{@code picocli.color.options}</li>
4205             *     <li>{@code picocli.color.parameters}</li>
4206             *     <li>{@code picocli.color.optionParams}</li>
4207             * </ul><p>Property values can be anything that {@link Help.Ansi.Style#parse(String)} can handle.</p>
4208             * @return this ColorScheme
4209             */
4210            public ColorScheme applySystemProperties() {
4211                replace(commandStyles,     System.getProperty("picocli.color.commands"));
4212                replace(optionStyles,      System.getProperty("picocli.color.options"));
4213                replace(parameterStyles,   System.getProperty("picocli.color.parameters"));
4214                replace(optionParamStyles, System.getProperty("picocli.color.optionParams"));
4215                return this;
4216            }
4217            private void replace(final List<IStyle> styles, final String property) {
4218                if (property != null) {
4219                    styles.clear();
4220                    addAll(styles, Style.parse(property));
4221                }
4222            }
4223            private ColorScheme addAll(final List<IStyle> styles, final IStyle... add) {
4224                styles.addAll(Arrays.asList(add));
4225                return this;
4226            }
4227
4228            public Ansi ansi() {
4229                return ansi;
4230            }
4231        }
4232
4233        /** Creates and returns a new {@link ColorScheme} initialized with picocli default values: commands are bold,
4234         *  options and parameters use a yellow foreground, and option parameters use italic.
4235         * @param ansi whether the usage help message should contain ANSI escape codes or not
4236         * @return a new default color scheme
4237         */
4238        public static ColorScheme defaultColorScheme(final Ansi ansi) {
4239            return new ColorScheme(ansi)
4240                    .commands(Style.bold)
4241                    .options(Style.fg_yellow)
4242                    .parameters(Style.fg_yellow)
4243                    .optionParams(Style.italic);
4244        }
4245
4246        /** Provides methods and inner classes to support using ANSI escape codes in usage help messages. */
4247        public enum Ansi {
4248            /** Only emit ANSI escape codes if the platform supports it and system property {@code "picocli.ansi"}
4249             * is not set to any value other than {@code "true"} (case insensitive). */
4250            AUTO,
4251            /** Forced ON: always emit ANSI escape code regardless of the platform. */
4252            ON,
4253            /** Forced OFF: never emit ANSI escape code regardless of the platform. */
4254            OFF;
4255            static Text EMPTY_TEXT = OFF.new Text(0);
4256            static final boolean isWindows  = System.getProperty("os.name").startsWith("Windows");
4257            static final boolean isXterm    = System.getenv("TERM") != null && System.getenv("TERM").startsWith("xterm");
4258            static final boolean ISATTY = calcTTY();
4259
4260            // http://stackoverflow.com/questions/1403772/how-can-i-check-if-a-java-programs-input-output-streams-are-connected-to-a-term
4261            static final boolean calcTTY() {
4262                if (isWindows && isXterm) { return true; } // Cygwin uses pseudo-tty and console is always null...
4263                try { return System.class.getDeclaredMethod("console").invoke(null) != null; }
4264                catch (final Throwable reflectionFailed) { return true; }
4265            }
4266            private static boolean ansiPossible() { return ISATTY && (!isWindows || isXterm); }
4267
4268            /** Returns {@code true} if ANSI escape codes should be emitted, {@code false} otherwise.
4269             * @return ON: {@code true}, OFF: {@code false}, AUTO: if system property {@code "picocli.ansi"} is
4270             *      defined then return its boolean value, otherwise return whether the platform supports ANSI escape codes */
4271            public boolean enabled() {
4272                if (this == ON)  { return true; }
4273                if (this == OFF) { return false; }
4274                return (System.getProperty("picocli.ansi") == null ? ansiPossible() : Boolean.getBoolean("picocli.ansi"));
4275            }
4276
4277            /** Defines the interface for an ANSI escape sequence. */
4278            public interface IStyle {
4279
4280                /** The Control Sequence Introducer (CSI) escape sequence {@value}. */
4281                String CSI = "\u001B[";
4282
4283                /** Returns the ANSI escape code for turning this style on.
4284                 * @return the ANSI escape code for turning this style on */
4285                String on();
4286
4287                /** Returns the ANSI escape code for turning this style off.
4288                 * @return the ANSI escape code for turning this style off */
4289                String off();
4290            }
4291
4292            /**
4293             * A set of pre-defined ANSI escape code styles and colors, and a set of convenience methods for parsing
4294             * text with embedded markup style names, as well as convenience methods for converting
4295             * styles to strings with embedded escape codes.
4296             */
4297            public enum Style implements IStyle {
4298                reset(0, 0), bold(1, 21), faint(2, 22), italic(3, 23), underline(4, 24), blink(5, 25), reverse(7, 27),
4299                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),
4300                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),
4301                ;
4302                private final int startCode;
4303                private final int endCode;
4304
4305                Style(final int startCode, final int endCode) {this.startCode = startCode; this.endCode = endCode; }
4306                @Override
4307                public String on() { return CSI + startCode + "m"; }
4308                @Override
4309                public String off() { return CSI + endCode + "m"; }
4310
4311                                /** Returns the concatenated ANSI escape codes for turning all specified styles on.
4312                 * @param styles the styles to generate ANSI escape codes for
4313                 * @return the concatenated ANSI escape codes for turning all specified styles on */
4314                public static String on(final IStyle... styles) {
4315                    final StringBuilder result = new StringBuilder();
4316                    for (final IStyle style : styles) {
4317                        result.append(style.on());
4318                    }
4319                    return result.toString();
4320                }
4321                                /** Returns the concatenated ANSI escape codes for turning all specified styles off.
4322                 * @param styles the styles to generate ANSI escape codes for
4323                 * @return the concatenated ANSI escape codes for turning all specified styles off */
4324                public static String off(final IStyle... styles) {
4325                    final StringBuilder result = new StringBuilder();
4326                    for (final IStyle style : styles) {
4327                        result.append(style.off());
4328                    }
4329                    return result.toString();
4330                }
4331                                /** Parses the specified style markup and returns the associated style.
4332                                 *  The markup may be one of the Style enum value names, or it may be one of the Style enum value
4333                                 *  names when {@code "fg_"} is prepended, or it may be one of the indexed colors in the 256 color palette.
4334                 * @param str the case-insensitive style markup to convert, e.g. {@code "blue"} or {@code "fg_blue"},
4335                 *          or {@code "46"} (indexed color) or {@code "0;5;0"} (RGB components of an indexed color)
4336                                 * @return the IStyle for the specified converter
4337                                 */
4338                public static IStyle fg(final String str) {
4339                    try { return Style.valueOf(str.toLowerCase(ENGLISH)); } catch (final Exception ignored) {}
4340                    try { return Style.valueOf("fg_" + str.toLowerCase(ENGLISH)); } catch (final Exception ignored) {}
4341                    return new Palette256Color(true, str);
4342                }
4343                                /** Parses the specified style markup and returns the associated style.
4344                                 *  The markup may be one of the Style enum value names, or it may be one of the Style enum value
4345                                 *  names when {@code "bg_"} is prepended, or it may be one of the indexed colors in the 256 color palette.
4346                                 * @param str the case-insensitive style markup to convert, e.g. {@code "blue"} or {@code "bg_blue"},
4347                 *          or {@code "46"} (indexed color) or {@code "0;5;0"} (RGB components of an indexed color)
4348                                 * @return the IStyle for the specified converter
4349                                 */
4350                public static IStyle bg(final String str) {
4351                    try { return Style.valueOf(str.toLowerCase(ENGLISH)); } catch (final Exception ignored) {}
4352                    try { return Style.valueOf("bg_" + str.toLowerCase(ENGLISH)); } catch (final Exception ignored) {}
4353                    return new Palette256Color(false, str);
4354                }
4355                /** Parses the specified comma-separated sequence of style descriptors and returns the associated
4356                 *  styles. For each markup, strings starting with {@code "bg("} are delegated to
4357                 *  {@link #bg(String)}, others are delegated to {@link #bg(String)}.
4358                 * @param commaSeparatedCodes one or more descriptors, e.g. {@code "bg(blue),underline,red"}
4359                 * @return an array with all styles for the specified descriptors
4360                 */
4361                public static IStyle[] parse(final String commaSeparatedCodes) {
4362                    final String[] codes = commaSeparatedCodes.split(",");
4363                    final IStyle[] styles = new IStyle[codes.length];
4364                    for(int i = 0; i < codes.length; ++i) {
4365                        if (codes[i].toLowerCase(ENGLISH).startsWith("fg(")) {
4366                            final int end = codes[i].indexOf(')');
4367                            styles[i] = Style.fg(codes[i].substring(3, end < 0 ? codes[i].length() : end));
4368                        } else if (codes[i].toLowerCase(ENGLISH).startsWith("bg(")) {
4369                            final int end = codes[i].indexOf(')');
4370                            styles[i] = Style.bg(codes[i].substring(3, end < 0 ? codes[i].length() : end));
4371                        } else {
4372                            styles[i] = Style.fg(codes[i]);
4373                        }
4374                    }
4375                    return styles;
4376                }
4377            }
4378
4379            /** Defines a palette map of 216 colors: 6 * 6 * 6 cube (216 colors):
4380             * 16 + 36 * r + 6 * g + b (0 &lt;= r, g, b &lt;= 5). */
4381            static class Palette256Color implements IStyle {
4382                private final int fgbg;
4383                private final int color;
4384
4385                Palette256Color(final boolean foreground, final String color) {
4386                    this.fgbg = foreground ? 38 : 48;
4387                    final String[] rgb = color.split(";");
4388                    if (rgb.length == 3) {
4389                        this.color = 16 + 36 * Integer.decode(rgb[0]) + 6 * Integer.decode(rgb[1]) + Integer.decode(rgb[2]);
4390                    } else {
4391                        this.color = Integer.decode(color);
4392                    }
4393                }
4394                @Override
4395                public String on() { return String.format(CSI + "%d;5;%dm", fgbg, color); }
4396                @Override
4397                public String off() { return CSI + (fgbg + 1) + "m"; }
4398            }
4399            private static class StyledSection {
4400                int startIndex, length;
4401                String startStyles, endStyles;
4402                StyledSection(final int start, final int len, final String style1, final String style2) {
4403                    startIndex = start; length = len; startStyles = style1; endStyles = style2;
4404                }
4405                StyledSection withStartIndex(final int newStart) {
4406                    return new StyledSection(newStart, length, startStyles, endStyles);
4407                }
4408            }
4409
4410            /**
4411             * Returns a new Text object where all the specified styles are applied to the full length of the
4412             * specified plain text.
4413             * @param plainText the string to apply all styles to. Must not contain markup!
4414             * @param styles the styles to apply to the full plain text
4415             * @return a new Text object
4416             */
4417            public Text apply(final String plainText, final List<IStyle> styles) {
4418                if (plainText.length() == 0) { return new Text(0); }
4419                final Text result = new Text(plainText.length());
4420                final IStyle[] all = styles.toArray(new IStyle[styles.size()]);
4421                result.sections.add(new StyledSection(
4422                        0, plainText.length(), Style.on(all), Style.off(reverse(all)) + Style.reset.off()));
4423                result.plain.append(plainText);
4424                result.length = result.plain.length();
4425                return result;
4426            }
4427
4428            private static <T> T[] reverse(final T[] all) {
4429                for (int i = 0; i < all.length / 2; i++) {
4430                    final T temp = all[i];
4431                    all[i] = all[all.length - i - 1];
4432                    all[all.length - i - 1] = temp;
4433                }
4434                return all;
4435            }
4436            /** Encapsulates rich text with styles and colors. Text objects may be constructed with Strings containing
4437             * markup like {@code @|bg(red),white,underline some text|@}, and this class converts the markup to ANSI
4438             * escape codes.
4439             * <p>
4440             * Internally keeps both an enriched and a plain text representation to allow layout components to calculate
4441             * text width while remaining unaware of the embedded ANSI escape codes.</p> */
4442            public class Text implements Cloneable {
4443                private final int maxLength;
4444                private int from;
4445                private int length;
4446                private StringBuilder plain = new StringBuilder();
4447                private List<StyledSection> sections = new ArrayList<>();
4448
4449                /** Constructs a Text with the specified max length (for use in a TextTable Column).
4450                 * @param maxLength max length of this text */
4451                public Text(final int maxLength) { this.maxLength = maxLength; }
4452
4453                /**
4454                 * Constructs a Text with the specified String, which may contain markup like
4455                 * {@code @|bg(red),white,underline some text|@}.
4456                 * @param input the string with markup to parse
4457                 */
4458                public Text(final String input) {
4459                    maxLength = -1;
4460                    plain.setLength(0);
4461                    int i = 0;
4462
4463                    while (true) {
4464                        int j = input.indexOf("@|", i);
4465                        if (j == -1) {
4466                            if (i == 0) {
4467                                plain.append(input);
4468                                length = plain.length();
4469                                return;
4470                            }
4471                            plain.append(input.substring(i, input.length()));
4472                            length = plain.length();
4473                            return;
4474                        }
4475                        plain.append(input.substring(i, j));
4476                        final int k = input.indexOf("|@", j);
4477                        if (k == -1) {
4478                            plain.append(input);
4479                            length = plain.length();
4480                            return;
4481                        }
4482
4483                        j += 2;
4484                        final String spec = input.substring(j, k);
4485                        final String[] items = spec.split(" ", 2);
4486                        if (items.length == 1) {
4487                            plain.append(input);
4488                            length = plain.length();
4489                            return;
4490                        }
4491
4492                        final IStyle[] styles = Style.parse(items[0]);
4493                        addStyledSection(plain.length(), items[1].length(),
4494                                Style.on(styles), Style.off(reverse(styles)) + Style.reset.off());
4495                        plain.append(items[1]);
4496                        i = k + 2;
4497                    }
4498                }
4499                private void addStyledSection(final int start, final int length, final String startStyle, final String endStyle) {
4500                    sections.add(new StyledSection(start, length, startStyle, endStyle));
4501                }
4502                @Override
4503                public Object clone() {
4504                    try { return super.clone(); } catch (final CloneNotSupportedException e) { throw new IllegalStateException(e); }
4505                }
4506
4507                public Text[] splitLines() {
4508                    final List<Text> result = new ArrayList<>();
4509                    boolean trailingEmptyString = false;
4510                    int start = 0, end = 0;
4511                    for (int i = 0; i < plain.length(); i++, end = i) {
4512                        final char c = plain.charAt(i);
4513                        boolean eol = c == '\n';
4514                        eol |= (c == '\r' && i + 1 < plain.length() && plain.charAt(i + 1) == '\n' && ++i > 0); // \r\n
4515                        eol |= c == '\r';
4516                        if (eol) {
4517                            result.add(this.substring(start, end));
4518                            trailingEmptyString = i == plain.length() - 1;
4519                            start = i + 1;
4520                        }
4521                    }
4522                    if (start < plain.length() || trailingEmptyString) {
4523                        result.add(this.substring(start, plain.length()));
4524                    }
4525                    return result.toArray(new Text[result.size()]);
4526                }
4527
4528                /** Returns a new {@code Text} instance that is a substring of this Text. Does not modify this instance!
4529                 * @param start index in the plain text where to start the substring
4530                 * @return a new Text instance that is a substring of this Text */
4531                public Text substring(final int start) {
4532                    return substring(start, length);
4533                }
4534
4535                /** Returns a new {@code Text} instance that is a substring of this Text. Does not modify this instance!
4536                 * @param start index in the plain text where to start the substring
4537                 * @param end index in the plain text where to end the substring
4538                 * @return a new Text instance that is a substring of this Text */
4539                public Text substring(final int start, final int end) {
4540                    final Text result = (Text) clone();
4541                    result.from = from + start;
4542                    result.length = end - start;
4543                    return result;
4544                }
4545                /** Returns a new {@code Text} instance with the specified text appended. Does not modify this instance!
4546                 * @param string the text to append
4547                 * @return a new Text instance */
4548                public Text append(final String string) {
4549                    return append(new Text(string));
4550                }
4551
4552                /** Returns a new {@code Text} instance with the specified text appended. Does not modify this instance!
4553                 * @param other the text to append
4554                 * @return a new Text instance */
4555                public Text append(final Text other) {
4556                    final Text result = (Text) clone();
4557                    result.plain = new StringBuilder(plain.toString().substring(from, from + length));
4558                    result.from = 0;
4559                    result.sections = new ArrayList<>();
4560                    for (final StyledSection section : sections) {
4561                        result.sections.add(section.withStartIndex(section.startIndex - from));
4562                    }
4563                    result.plain.append(other.plain.toString().substring(other.from, other.from + other.length));
4564                    for (final StyledSection section : other.sections) {
4565                        final int index = result.length + section.startIndex - other.from;
4566                        result.sections.add(section.withStartIndex(index));
4567                    }
4568                    result.length = result.plain.length();
4569                    return result;
4570                }
4571
4572                /**
4573                 * Copies the specified substring of this Text into the specified destination, preserving the markup.
4574                 * @param from start of the substring
4575                 * @param length length of the substring
4576                 * @param destination destination Text to modify
4577                 * @param offset indentation (padding)
4578                 */
4579                public void getStyledChars(final int from, final int length, final Text destination, final int offset) {
4580                    if (destination.length < offset) {
4581                        for (int i = destination.length; i < offset; i++) {
4582                            destination.plain.append(' ');
4583                        }
4584                        destination.length = offset;
4585                    }
4586                    for (final StyledSection section : sections) {
4587                        destination.sections.add(section.withStartIndex(section.startIndex - from + destination.length));
4588                    }
4589                    destination.plain.append(plain.toString().substring(from, from + length));
4590                    destination.length = destination.plain.length();
4591                }
4592                /** Returns the plain text without any formatting.
4593                 * @return the plain text without any formatting */
4594                public String plainString() {  return plain.toString().substring(from, from + length); }
4595
4596                @Override
4597                public boolean equals(final Object obj) { return toString().equals(String.valueOf(obj)); }
4598                @Override
4599                public int hashCode() { return toString().hashCode(); }
4600
4601                /** Returns a String representation of the text with ANSI escape codes embedded, unless ANSI is
4602                 * {@linkplain Ansi#enabled()} not enabled}, in which case the plain text is returned.
4603                 * @return a String representation of the text with ANSI escape codes embedded (if enabled) */
4604                @Override
4605                public String toString() {
4606                    if (!Ansi.this.enabled()) {
4607                        return plain.toString().substring(from, from + length);
4608                    }
4609                    if (length == 0) { return ""; }
4610                    final StringBuilder sb = new StringBuilder(plain.length() + 20 * sections.size());
4611                    StyledSection current = null;
4612                    final int end = Math.min(from + length, plain.length());
4613                    for (int i = from; i < end; i++) {
4614                        final StyledSection section = findSectionContaining(i);
4615                        if (section != current) {
4616                            if (current != null) { sb.append(current.endStyles); }
4617                            if (section != null) { sb.append(section.startStyles); }
4618                            current = section;
4619                        }
4620                        sb.append(plain.charAt(i));
4621                    }
4622                    if (current != null) { sb.append(current.endStyles); }
4623                    return sb.toString();
4624                }
4625
4626                private StyledSection findSectionContaining(final int index) {
4627                    for (final StyledSection section : sections) {
4628                        if (index >= section.startIndex && index < section.startIndex + section.length) {
4629                            return section;
4630                        }
4631                    }
4632                    return null;
4633                }
4634            }
4635        }
4636    }
4637
4638    /**
4639     * Utility class providing some defensive coding convenience methods.
4640     */
4641    private static final class Assert {
4642        /**
4643         * Throws a NullPointerException if the specified object is null.
4644         * @param object the object to verify
4645         * @param description error message
4646         * @param <T> type of the object to check
4647         * @return the verified object
4648         */
4649        static <T> T notNull(final T object, final String description) {
4650            if (object == null) {
4651                throw new NullPointerException(description);
4652            }
4653            return object;
4654        }
4655        private Assert() {} // private constructor: never instantiate
4656    }
4657    private enum TraceLevel { OFF, WARN, INFO, DEBUG;
4658        public boolean isEnabled(final TraceLevel other) { return ordinal() >= other.ordinal(); }
4659        private void print(final Tracer tracer, final String msg, final Object... params) {
4660            if (tracer.level.isEnabled(this)) { tracer.stream.printf(prefix(msg), params); }
4661        }
4662        private String prefix(final String msg) { return "[picocli " + this + "] " + msg; }
4663        static TraceLevel lookup(final String key) { return key == null ? WARN : empty(key) || "true".equalsIgnoreCase(key) ? INFO : valueOf(key); }
4664    }
4665    private static class Tracer {
4666        TraceLevel level = TraceLevel.lookup(System.getProperty("picocli.trace"));
4667        PrintStream stream = System.err;
4668        void warn (final String msg, final Object... params) { TraceLevel.WARN.print(this, msg, params); }
4669        void info (final String msg, final Object... params) { TraceLevel.INFO.print(this, msg, params); }
4670        void debug(final String msg, final Object... params) { TraceLevel.DEBUG.print(this, msg, params); }
4671        boolean isWarn()  { return level.isEnabled(TraceLevel.WARN); }
4672        boolean isInfo()  { return level.isEnabled(TraceLevel.INFO); }
4673        boolean isDebug() { return level.isEnabled(TraceLevel.DEBUG); }
4674    }
4675    /** Base class of all exceptions thrown by {@code picocli.CommandLine}.
4676     * @since 2.0 */
4677    public static class PicocliException extends RuntimeException {
4678        private static final long serialVersionUID = -2574128880125050818L;
4679        public PicocliException(final String msg) { super(msg); }
4680        public PicocliException(final String msg, final Exception ex) { super(msg, ex); }
4681    }
4682    /** Exception indicating a problem during {@code CommandLine} initialization.
4683     * @since 2.0 */
4684    public static class InitializationException extends PicocliException {
4685        private static final long serialVersionUID = 8423014001666638895L;
4686        public InitializationException(final String msg) { super(msg); }
4687        public InitializationException(final String msg, final Exception ex) { super(msg, ex); }
4688    }
4689    /** Exception indicating a problem while invoking a command or subcommand.
4690     * @since 2.0 */
4691    public static class ExecutionException extends PicocliException {
4692        private static final long serialVersionUID = 7764539594267007998L;
4693        private final CommandLine commandLine;
4694        public ExecutionException(final CommandLine commandLine, final String msg) {
4695            super(msg);
4696            this.commandLine = Assert.notNull(commandLine, "commandLine");
4697        }
4698        public ExecutionException(final CommandLine commandLine, final String msg, final Exception ex) {
4699            super(msg, ex);
4700            this.commandLine = Assert.notNull(commandLine, "commandLine");
4701        }
4702        /** Returns the {@code CommandLine} object for the (sub)command that could not be invoked.
4703         * @return the {@code CommandLine} object for the (sub)command where invocation failed.
4704         */
4705        public CommandLine getCommandLine() { return commandLine; }
4706    }
4707
4708    /** Exception thrown by {@link ITypeConverter} implementations to indicate a String could not be converted. */
4709    public static class TypeConversionException extends PicocliException {
4710        private static final long serialVersionUID = 4251973913816346114L;
4711        public TypeConversionException(final String msg) { super(msg); }
4712    }
4713    /** Exception indicating something went wrong while parsing command line options. */
4714    public static class ParameterException extends PicocliException {
4715        private static final long serialVersionUID = 1477112829129763139L;
4716        private final CommandLine commandLine;
4717
4718        /** Constructs a new ParameterException with the specified CommandLine and error message.
4719         * @param commandLine the command or subcommand whose input was invalid
4720         * @param msg describes the problem
4721         * @since 2.0 */
4722        public ParameterException(final CommandLine commandLine, final String msg) {
4723            super(msg);
4724            this.commandLine = Assert.notNull(commandLine, "commandLine");
4725        }
4726        /** Constructs a new ParameterException with the specified CommandLine and error message.
4727         * @param commandLine the command or subcommand whose input was invalid
4728         * @param msg describes the problem
4729         * @param ex the exception that caused this ParameterException
4730         * @since 2.0 */
4731        public ParameterException(final CommandLine commandLine, final String msg, final Exception ex) {
4732            super(msg, ex);
4733            this.commandLine = Assert.notNull(commandLine, "commandLine");
4734        }
4735
4736        /** Returns the {@code CommandLine} object for the (sub)command whose input could not be parsed.
4737         * @return the {@code CommandLine} object for the (sub)command where parsing failed.
4738         * @since 2.0
4739         */
4740        public CommandLine getCommandLine() { return commandLine; }
4741
4742        private static ParameterException create(final CommandLine cmd, final Exception ex, final String arg, final int i, final String[] args) {
4743            final String msg = ex.getClass().getSimpleName() + ": " + ex.getLocalizedMessage()
4744                    + " while processing argument at or before arg[" + i + "] '" + arg + "' in " + Arrays.toString(args) + ": " + ex.toString();
4745            return new ParameterException(cmd, msg, ex);
4746        }
4747    }
4748    /**
4749     * Exception indicating that a required parameter was not specified.
4750     */
4751    public static class MissingParameterException extends ParameterException {
4752        private static final long serialVersionUID = 5075678535706338753L;
4753        public MissingParameterException(final CommandLine commandLine, final String msg) {
4754            super(commandLine, msg);
4755        }
4756
4757        private static MissingParameterException create(final CommandLine cmd, final Collection<Field> missing, final String separator) {
4758            if (missing.size() == 1) {
4759                return new MissingParameterException(cmd, "Missing required option '"
4760                        + describe(missing.iterator().next(), separator) + "'");
4761            }
4762            final List<String> names = new ArrayList<>(missing.size());
4763            for (final Field field : missing) {
4764                names.add(describe(field, separator));
4765            }
4766            return new MissingParameterException(cmd, "Missing required options " + names.toString());
4767        }
4768        private static String describe(final Field field, final String separator) {
4769            final String prefix = (field.isAnnotationPresent(Option.class))
4770                ? field.getAnnotation(Option.class).names()[0] + separator
4771                : "params[" + field.getAnnotation(Parameters.class).index() + "]" + separator;
4772            return prefix + Help.DefaultParamLabelRenderer.renderParameterName(field);
4773        }
4774    }
4775
4776    /**
4777     * Exception indicating that multiple fields have been annotated with the same Option name.
4778     */
4779    public static class DuplicateOptionAnnotationsException extends InitializationException {
4780        private static final long serialVersionUID = -3355128012575075641L;
4781        public DuplicateOptionAnnotationsException(final String msg) { super(msg); }
4782
4783        private static DuplicateOptionAnnotationsException create(final String name, final Field field1, final Field field2) {
4784            return new DuplicateOptionAnnotationsException("Option name '" + name + "' is used by both " +
4785                    field1.getDeclaringClass().getName() + "." + field1.getName() + " and " +
4786                    field2.getDeclaringClass().getName() + "." + field2.getName());
4787        }
4788    }
4789    /** Exception indicating that there was a gap in the indices of the fields annotated with {@link Parameters}. */
4790    public static class ParameterIndexGapException extends InitializationException {
4791        private static final long serialVersionUID = -1520981133257618319L;
4792        public ParameterIndexGapException(final String msg) { super(msg); }
4793    }
4794    /** Exception indicating that a command line argument could not be mapped to any of the fields annotated with
4795     * {@link Option} or {@link Parameters}. */
4796    public static class UnmatchedArgumentException extends ParameterException {
4797        private static final long serialVersionUID = -8700426380701452440L;
4798        public UnmatchedArgumentException(final CommandLine commandLine, final String msg) { super(commandLine, msg); }
4799        public UnmatchedArgumentException(final CommandLine commandLine, final Stack<String> args) { this(commandLine, new ArrayList<>(reverse(args))); }
4800        public UnmatchedArgumentException(final CommandLine commandLine, final List<String> args) { this(commandLine, "Unmatched argument" + (args.size() == 1 ? " " : "s ") + args); }
4801    }
4802    /** Exception indicating that more values were specified for an option or parameter than its {@link Option#arity() arity} allows. */
4803    public static class MaxValuesforFieldExceededException extends ParameterException {
4804        private static final long serialVersionUID = 6536145439570100641L;
4805        public MaxValuesforFieldExceededException(final CommandLine commandLine, final String msg) { super(commandLine, msg); }
4806    }
4807    /** Exception indicating that an option for a single-value option field has been specified multiple times on the command line. */
4808    public static class OverwrittenOptionException extends ParameterException {
4809        private static final long serialVersionUID = 1338029208271055776L;
4810        public OverwrittenOptionException(final CommandLine commandLine, final String msg) { super(commandLine, msg); }
4811    }
4812    /**
4813     * Exception indicating that an annotated field had a type for which no {@link ITypeConverter} was
4814     * {@linkplain #registerConverter(Class, ITypeConverter) registered}.
4815     */
4816    public static class MissingTypeConverterException extends ParameterException {
4817        private static final long serialVersionUID = -6050931703233083760L;
4818        public MissingTypeConverterException(final CommandLine commandLine, final String msg) { super(commandLine, msg); }
4819    }
4820}