View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.tools.picocli;
18  
19  import java.io.File;
20  import java.io.PrintStream;
21  import java.lang.annotation.ElementType;
22  import java.lang.annotation.Retention;
23  import java.lang.annotation.RetentionPolicy;
24  import java.lang.annotation.Target;
25  import java.lang.reflect.Array;
26  import java.lang.reflect.Constructor;
27  import java.lang.reflect.Field;
28  import java.lang.reflect.ParameterizedType;
29  import java.lang.reflect.Type;
30  import java.lang.reflect.WildcardType;
31  import java.math.BigDecimal;
32  import java.math.BigInteger;
33  import java.net.InetAddress;
34  import java.net.MalformedURLException;
35  import java.net.URI;
36  import java.net.URISyntaxException;
37  import java.net.URL;
38  import java.nio.charset.Charset;
39  import java.nio.file.Path;
40  import java.nio.file.Paths;
41  import java.sql.Time;
42  import java.text.BreakIterator;
43  import java.text.ParseException;
44  import java.text.SimpleDateFormat;
45  import java.util.ArrayList;
46  import java.util.Arrays;
47  import java.util.Collection;
48  import java.util.Collections;
49  import java.util.Comparator;
50  import java.util.Date;
51  import java.util.HashMap;
52  import java.util.HashSet;
53  import java.util.LinkedHashMap;
54  import java.util.LinkedHashSet;
55  import java.util.LinkedList;
56  import java.util.List;
57  import java.util.Map;
58  import java.util.Queue;
59  import java.util.Set;
60  import java.util.SortedSet;
61  import java.util.Stack;
62  import java.util.TreeSet;
63  import java.util.UUID;
64  import java.util.concurrent.Callable;
65  import java.util.regex.Pattern;
66  
67  import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.IStyle;
68  import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.Style;
69  import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Ansi.Text;
70  
71  import static java.util.Locale.ENGLISH;
72  import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.SPAN;
73  import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.TRUNCATE;
74  import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Column.Overflow.WRAP;
75  
76  /**
77   * <p>
78   * CommandLine interpreter that uses reflection to initialize an annotated domain object with values obtained from the
79   * command line arguments.
80   * </p><h2>Example</h2>
81   * <pre>import static picocli.CommandLine.*;
82   *
83   * &#064;Command(header = "Encrypt FILE(s), or standard input, to standard output or to the output file.",
84   *          version = "v1.2.3")
85   * public class Encrypt {
86   *
87   *     &#064;Parameters(type = File.class, description = "Any number of input files")
88   *     private List&lt;File&gt; files = new ArrayList&lt;File&gt;();
89   *
90   *     &#064;Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
91   *     private File outputFile;
92   *
93   *     &#064;Option(names = { "-v", "--verbose"}, description = "Verbosely list files processed")
94   *     private boolean verbose;
95   *
96   *     &#064;Option(names = { "-h", "--help", "-?", "-help"}, usageHelp = true, description = "Display this help and exit")
97   *     private boolean help;
98   *
99   *     &#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  */
133 public 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<String>();
143     private CommandLine parent;
144     private boolean usageHelpRequested;
145     private boolean versionHelpRequested;
146     private final List<String> versionLines = new ArrayList<String>();
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<String, CommandLine>(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<Object>();
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<String, CommandLine>();
1860         private final Map<Class<?>, ITypeConverter<?>> converterRegistry = new HashMap<Class<?>, ITypeConverter<?>>();
1861         private final Map<String, Field> optionName2Field                = new HashMap<String, Field>();
1862         private final Map<Character, Field> singleCharOption2Field       = new HashMap<Character, Field>();
1863         private final List<Field> requiredFields                         = new ArrayList<Field>();
1864         private final List<Field> positionalParametersFields             = new ArrayList<Field>();
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<String>();
1963             for (int i = args.length - 1; i >= 0; i--) {
1964                 arguments.push(args[i]);
1965             }
1966             final List<CommandLine> result = new ArrayList<CommandLine>();
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<Field>(optionName2Field.values()).size(), positionalParametersFields.size(), requiredFields.size(), commands.size());}
1979             parsedCommands.add(CommandLine.this);
1980             final List<Field> required = new ArrayList<Field>(requiredFields);
1981             final Set<Field> initialized = new HashSet<Field>();
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 {
2059                         if (tracer.isDebug()) {tracer.debug("'%s' contains separator '%s' but '%s' is not a known option%n", arg, separator, key);}
2060                     }
2061                 } else {
2062                     if (tracer.isDebug()) {tracer.debug("'%s' cannot be separated into <option>%s<option-parameter>%n", arg, separator);}
2063                 }
2064                 if (optionName2Field.containsKey(arg)) {
2065                     processStandaloneOption(required, initialized, arg, args, paramAttachedToOption);
2066                 }
2067                 // Compact (single-letter) options can be grouped with other options or with an argument.
2068                 // only single-letter options can be combined with other options or with an argument
2069                 else if (arg.length() > 2 && arg.startsWith("-")) {
2070                     if (tracer.isDebug()) {tracer.debug("Trying to process '%s' as clustered short options%n", arg, args);}
2071                     processClusteredShortOptions(required, initialized, arg, args);
2072                 }
2073                 // The argument could not be interpreted as an option.
2074                 // We take this to mean that the remainder are positional arguments
2075                 else {
2076                     args.push(arg);
2077                     if (tracer.isDebug()) {tracer.debug("Could not find option '%s', deciding whether to treat as unmatched option or positional parameter...%n", arg);}
2078                     if (resemblesOption(arg)) { handleUnmatchedArguments(args.pop()); continue; } // #149
2079                     if (tracer.isDebug()) {tracer.debug("No option named '%s' found. Processing remainder as positional parameters%n", arg);}
2080                     processPositionalParameter(required, initialized, args);
2081                 }
2082             }
2083         }
2084         private boolean resemblesOption(final String arg) {
2085             int count = 0;
2086             for (final String optionName : optionName2Field.keySet()) {
2087                 for (int i = 0; i < arg.length(); i++) {
2088                     if (optionName.length() > i && arg.charAt(i) == optionName.charAt(i)) { count++; } else { break; }
2089                 }
2090             }
2091             final boolean result = count > 0 && count * 10 >= optionName2Field.size() * 9; // at least one prefix char in common with 9 out of 10 options
2092             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());}
2093             return result;
2094         }
2095         private void handleUnmatchedArguments(final String arg) {final Stack<String> args = new Stack<String>(); args.add(arg); handleUnmatchedArguments(args);}
2096         private void handleUnmatchedArguments(final Stack<String> args) {
2097             while (!args.isEmpty()) { unmatchedArguments.add(args.pop()); } // addAll would give args in reverse order
2098         }
2099 
2100         private void processRemainderAsPositionalParameters(final Collection<Field> required, final Set<Field> initialized, final Stack<String> args) throws Exception {
2101             while (!args.empty()) {
2102                 processPositionalParameter(required, initialized, args);
2103             }
2104         }
2105         private void processPositionalParameter(final Collection<Field> required, final Set<Field> initialized, final Stack<String> args) throws Exception {
2106             if (tracer.isDebug()) {tracer.debug("Processing next arg as a positional parameter at index=%d. Remainder=%s%n", position, reverse((Stack<String>) args.clone()));}
2107             int consumed = 0;
2108             for (final Field positionalParam : positionalParametersFields) {
2109                 final Range indexRange = Range.parameterIndex(positionalParam);
2110                 if (!indexRange.contains(position)) {
2111                     continue;
2112                 }
2113                 @SuppressWarnings("unchecked")
2114                 final
2115                 Stack<String> argsCopy = (Stack<String>) args.clone();
2116                 final Range arity = Range.parameterArity(positionalParam);
2117                 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);}
2118                 assertNoMissingParameters(positionalParam, arity.min, argsCopy);
2119                 final int originalSize = argsCopy.size();
2120                 applyOption(positionalParam, Parameters.class, arity, false, argsCopy, initialized, "args[" + indexRange + "] at position " + position);
2121                 final int count = originalSize - argsCopy.size();
2122                 if (count > 0) { required.remove(positionalParam); }
2123                 consumed = Math.max(consumed, count);
2124             }
2125             // remove processed args from the stack
2126             for (int i = 0; i < consumed; i++) { args.pop(); }
2127             position += consumed;
2128             if (tracer.isDebug()) {tracer.debug("Consumed %d arguments, moving position to index %d.%n", consumed, position);}
2129             if (consumed == 0 && !args.isEmpty()) {
2130                 handleUnmatchedArguments(args.pop());
2131             }
2132         }
2133 
2134         private void processStandaloneOption(final Collection<Field> required,
2135                                              final Set<Field> initialized,
2136                                              final String arg,
2137                                              final Stack<String> args,
2138                                              final boolean paramAttachedToKey) throws Exception {
2139             final Field field = optionName2Field.get(arg);
2140             required.remove(field);
2141             Range arity = Range.optionArity(field);
2142             if (paramAttachedToKey) {
2143                 arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1
2144             }
2145             if (tracer.isDebug()) {tracer.debug("Found option named '%s': field %s, arity=%s%n", arg, field, arity);}
2146             applyOption(field, Option.class, arity, paramAttachedToKey, args, initialized, "option " + arg);
2147         }
2148 
2149         private void processClusteredShortOptions(final Collection<Field> required,
2150                                                   final Set<Field> initialized,
2151                                                   final String arg,
2152                                                   final Stack<String> args)
2153                 throws Exception {
2154             final String prefix = arg.substring(0, 1);
2155             String cluster = arg.substring(1);
2156             boolean paramAttachedToOption = true;
2157             do {
2158                 if (cluster.length() > 0 && singleCharOption2Field.containsKey(cluster.charAt(0))) {
2159                     final Field field = singleCharOption2Field.get(cluster.charAt(0));
2160                     Range arity = Range.optionArity(field);
2161                     final String argDescription = "option " + prefix + cluster.charAt(0);
2162                     if (tracer.isDebug()) {tracer.debug("Found option '%s%s' in %s: field %s, arity=%s%n", prefix, cluster.charAt(0), arg, field, arity);}
2163                     required.remove(field);
2164                     cluster = cluster.length() > 0 ? cluster.substring(1) : "";
2165                     paramAttachedToOption = cluster.length() > 0;
2166                     if (cluster.startsWith(separator)) {// attached with separator, like -f=FILE or -v=true
2167                         cluster = cluster.substring(separator.length());
2168                         arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1
2169                     }
2170                     if (arity.min > 0 && !empty(cluster)) {
2171                         if (tracer.isDebug()) {tracer.debug("Trying to process '%s' as option parameter%n", cluster);}
2172                     }
2173                     // arity may be >= 1, or
2174                     // arity <= 0 && !cluster.startsWith(separator)
2175                     // e.g., boolean @Option("-v", arity=0, varargs=true); arg "-rvTRUE", remainder cluster="TRUE"
2176                     if (!empty(cluster)) {
2177                         args.push(cluster); // interpret remainder as option parameter
2178                     }
2179                     final int consumed = applyOption(field, Option.class, arity, paramAttachedToOption, args, initialized, argDescription);
2180                     // only return if cluster (and maybe more) was consumed, otherwise continue do-while loop
2181                     if (empty(cluster) || consumed > 0 || args.isEmpty()) {
2182                         return;
2183                     }
2184                     cluster = args.pop();
2185                 } else { // cluster is empty || cluster.charAt(0) is not a short option key
2186                     if (cluster.length() == 0) { // we finished parsing a group of short options like -rxv
2187                         return; // return normally and parse the next arg
2188                     }
2189                     // We get here when the remainder of the cluster group is neither an option,
2190                     // nor a parameter that the last option could consume.
2191                     if (arg.endsWith(cluster)) {
2192                         args.push(paramAttachedToOption ? prefix + cluster : cluster);
2193                         if (args.peek().equals(arg)) { // #149 be consistent between unmatched short and long options
2194                             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);}
2195                             if (resemblesOption(arg)) { handleUnmatchedArguments(args.pop()); return; } // #149
2196                             processPositionalParameter(required, initialized, args);
2197                             return;
2198                         }
2199                         // remainder was part of a clustered group that could not be completely parsed
2200                         if (tracer.isDebug()) {tracer.debug("No option found for %s in %s%n", cluster, arg);}
2201                         handleUnmatchedArguments(args.pop());
2202                     } else {
2203                         args.push(cluster);
2204                         if (tracer.isDebug()) {tracer.debug("%s is not an option parameter for %s%n", cluster, arg);}
2205                         processPositionalParameter(required, initialized, args);
2206                     }
2207                     return;
2208                 }
2209             } while (true);
2210         }
2211 
2212         private int applyOption(final Field field,
2213                                 final Class<?> annotation,
2214                                 final Range arity,
2215                                 final boolean valueAttachedToOption,
2216                                 final Stack<String> args,
2217                                 final Set<Field> initialized,
2218                                 final String argDescription) throws Exception {
2219             updateHelpRequested(field);
2220             final int length = args.size();
2221             assertNoMissingParameters(field, arity.min, args);
2222 
2223             Class<?> cls = field.getType();
2224             if (cls.isArray()) {
2225                 return applyValuesToArrayField(field, annotation, arity, args, cls, argDescription);
2226             }
2227             if (Collection.class.isAssignableFrom(cls)) {
2228                 return applyValuesToCollectionField(field, annotation, arity, args, cls, argDescription);
2229             }
2230             if (Map.class.isAssignableFrom(cls)) {
2231                 return applyValuesToMapField(field, annotation, arity, args, cls, argDescription);
2232             }
2233             cls = getTypeAttribute(field)[0]; // field may be interface/abstract type, use annotation to get concrete type
2234             return applyValueToSingleValuedField(field, arity, args, cls, initialized, argDescription);
2235         }
2236 
2237         private int applyValueToSingleValuedField(final Field field,
2238                                                   final Range arity,
2239                                                   final Stack<String> args,
2240                                                   final Class<?> cls,
2241                                                   final Set<Field> initialized,
2242                                                   final String argDescription) throws Exception {
2243             final boolean noMoreValues = args.isEmpty();
2244             String value = args.isEmpty() ? null : trim(args.pop()); // unquote the value
2245             int result = arity.min; // the number or args we need to consume
2246 
2247             // special logic for booleans: BooleanConverter accepts only "true" or "false".
2248             if ((cls == Boolean.class || cls == Boolean.TYPE) && arity.min <= 0) {
2249 
2250                 // boolean option with arity = 0..1 or 0..*: value MAY be a param
2251                 if (arity.max > 0 && ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value))) {
2252                     result = 1;            // if it is a varargs we only consume 1 argument if it is a boolean value
2253                 } else {
2254                     if (value != null) {
2255                         args.push(value); // we don't consume the value
2256                     }
2257                     final Boolean currentValue = (Boolean) field.get(command);
2258                     value = String.valueOf(currentValue == null ? true : !currentValue); // #147 toggle existing boolean value
2259                 }
2260             }
2261             if (noMoreValues && value == null) {
2262                 return 0;
2263             }
2264             final ITypeConverter<?> converter = getTypeConverter(cls, field);
2265             final Object newValue = tryConvert(field, -1, converter, value, cls);
2266             final Object oldValue = field.get(command);
2267             TraceLevel level = TraceLevel.INFO;
2268             String traceMessage = "Setting %s field '%s.%s' to '%5$s' (was '%4$s') for %6$s%n";
2269             if (initialized != null) {
2270                 if (initialized.contains(field)) {
2271                     if (!isOverwrittenOptionsAllowed()) {
2272                         throw new OverwrittenOptionException(CommandLine.this, optionDescription("", field, 0) +  " should be specified only once");
2273                     }
2274                     level = TraceLevel.WARN;
2275                     traceMessage = "Overwriting %s field '%s.%s' value '%s' with '%s' for %s%n";
2276                 }
2277                 initialized.add(field);
2278             }
2279             if (tracer.level.isEnabled(level)) { level.print(tracer, traceMessage, field.getType().getSimpleName(),
2280                         field.getDeclaringClass().getSimpleName(), field.getName(), String.valueOf(oldValue), String.valueOf(newValue), argDescription);
2281             }
2282             field.set(command, newValue);
2283             return result;
2284         }
2285         private int applyValuesToMapField(final Field field,
2286                                           final Class<?> annotation,
2287                                           final Range arity,
2288                                           final Stack<String> args,
2289                                           final Class<?> cls,
2290                                           final String argDescription) throws Exception {
2291             final Class<?>[] classes = getTypeAttribute(field);
2292             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."); }
2293             final ITypeConverter<?> keyConverter   = getTypeConverter(classes[0], field);
2294             final ITypeConverter<?> valueConverter = getTypeConverter(classes[1], field);
2295             Map<Object, Object> result = (Map<Object, Object>) field.get(command);
2296             if (result == null) {
2297                 result = createMap(cls);
2298                 field.set(command, result);
2299             }
2300             final int originalSize = result.size();
2301             consumeMapArguments(field, arity, args, classes, keyConverter, valueConverter, result, argDescription);
2302             return result.size() - originalSize;
2303         }
2304 
2305         private void consumeMapArguments(final Field field,
2306                                          final Range arity,
2307                                          final Stack<String> args,
2308                                          final Class<?>[] classes,
2309                                          final ITypeConverter<?> keyConverter,
2310                                          final ITypeConverter<?> valueConverter,
2311                                          final Map<Object, Object> result,
2312                                          final String argDescription) throws Exception {
2313             // first do the arity.min mandatory parameters
2314             for (int i = 0; i < arity.min; i++) {
2315                 consumeOneMapArgument(field, arity, args, classes, keyConverter, valueConverter, result, i, argDescription);
2316             }
2317             // now process the varargs if any
2318             for (int i = arity.min; i < arity.max && !args.isEmpty(); i++) {
2319                 if (!field.isAnnotationPresent(Parameters.class)) {
2320                     if (commands.containsKey(args.peek()) || isOption(args.peek())) {
2321                         return;
2322                     }
2323                 }
2324                 consumeOneMapArgument(field, arity, args, classes, keyConverter, valueConverter, result, i, argDescription);
2325             }
2326         }
2327 
2328         private void consumeOneMapArgument(final Field field,
2329                                            final Range arity,
2330                                            final Stack<String> args,
2331                                            final Class<?>[] classes,
2332                                            final ITypeConverter<?> keyConverter, final ITypeConverter<?> valueConverter,
2333                                            final Map<Object, Object> result,
2334                                            final int index,
2335                                            final String argDescription) throws Exception {
2336             final String[] values = split(trim(args.pop()), field);
2337             for (final String value : values) {
2338                 final String[] keyValue = value.split("=");
2339                 if (keyValue.length < 2) {
2340                     final String splitRegex = splitRegex(field);
2341                     if (splitRegex.length() == 0) {
2342                         throw new ParameterException(CommandLine.this, "Value for option " + optionDescription("", field,
2343                                 0) + " should be in KEY=VALUE format but was " + value);
2344                     } else {
2345                         throw new ParameterException(CommandLine.this, "Value for option " + optionDescription("", field,
2346                                 0) + " should be in KEY=VALUE[" + splitRegex + "KEY=VALUE]... format but was " + value);
2347                     }
2348                 }
2349                 final Object mapKey =   tryConvert(field, index, keyConverter,   keyValue[0], classes[0]);
2350                 final Object mapValue = tryConvert(field, index, valueConverter, keyValue[1], classes[1]);
2351                 result.put(mapKey, mapValue);
2352                 if (tracer.isInfo()) {tracer.info("Putting [%s : %s] in %s<%s, %s> field '%s.%s' for %s%n", String.valueOf(mapKey), String.valueOf(mapValue),
2353                         result.getClass().getSimpleName(), classes[0].getSimpleName(), classes[1].getSimpleName(), field.getDeclaringClass().getSimpleName(), field.getName(), argDescription);}
2354             }
2355         }
2356 
2357         private void checkMaxArityExceeded(final Range arity, final int remainder, final Field field, final String[] values) {
2358             if (values.length <= remainder) { return; }
2359             final String desc = arity.max == remainder ? "" + remainder : arity + ", remainder=" + remainder;
2360             throw new MaxValuesforFieldExceededException(CommandLine.this, optionDescription("", field, -1) +
2361                     " max number of values (" + arity.max + ") exceeded: remainder is " + remainder + " but " +
2362                     values.length + " values were specified: " + Arrays.toString(values));
2363         }
2364 
2365         private int applyValuesToArrayField(final Field field,
2366                                             final Class<?> annotation,
2367                                             final Range arity,
2368                                             final Stack<String> args,
2369                                             final Class<?> cls,
2370                                             final String argDescription) throws Exception {
2371             final Object existing = field.get(command);
2372             final int length = existing == null ? 0 : Array.getLength(existing);
2373             final Class<?> type = getTypeAttribute(field)[0];
2374             final List<Object> converted = consumeArguments(field, annotation, arity, args, type, length, argDescription);
2375             final List<Object> newValues = new ArrayList<Object>();
2376             for (int i = 0; i < length; i++) {
2377                 newValues.add(Array.get(existing, i));
2378             }
2379             for (final Object obj : converted) {
2380                 if (obj instanceof Collection<?>) {
2381                     newValues.addAll((Collection<?>) obj);
2382                 } else {
2383                     newValues.add(obj);
2384                 }
2385             }
2386             final Object array = Array.newInstance(type, newValues.size());
2387             field.set(command, array);
2388             for (int i = 0; i < newValues.size(); i++) {
2389                 Array.set(array, i, newValues.get(i));
2390             }
2391             return converted.size(); // return how many args were consumed
2392         }
2393 
2394         @SuppressWarnings("unchecked")
2395         private int applyValuesToCollectionField(final Field field,
2396                                                  final Class<?> annotation,
2397                                                  final Range arity,
2398                                                  final Stack<String> args,
2399                                                  final Class<?> cls,
2400                                                  final String argDescription) throws Exception {
2401             Collection<Object> collection = (Collection<Object>) field.get(command);
2402             final Class<?> type = getTypeAttribute(field)[0];
2403             final int length = collection == null ? 0 : collection.size();
2404             final List<Object> converted = consumeArguments(field, annotation, arity, args, type, length, argDescription);
2405             if (collection == null) {
2406                 collection = createCollection(cls);
2407                 field.set(command, collection);
2408             }
2409             for (final Object element : converted) {
2410                 if (element instanceof Collection<?>) {
2411                     collection.addAll((Collection<?>) element);
2412                 } else {
2413                     collection.add(element);
2414                 }
2415             }
2416             return converted.size();
2417         }
2418 
2419         private List<Object> consumeArguments(final Field field,
2420                                               final Class<?> annotation,
2421                                               final Range arity,
2422                                               final Stack<String> args,
2423                                               final Class<?> type,
2424                                               final int originalSize,
2425                                               final String argDescription) throws Exception {
2426             final List<Object> result = new ArrayList<Object>();
2427 
2428             // first do the arity.min mandatory parameters
2429             for (int i = 0; i < arity.min; i++) {
2430                 consumeOneArgument(field, arity, args, type, result, i, originalSize, argDescription);
2431             }
2432             // now process the varargs if any
2433             for (int i = arity.min; i < arity.max && !args.isEmpty(); i++) {
2434                 if (annotation != Parameters.class) { // for vararg Options, we stop if we encounter '--', a command, or another option
2435                     if (commands.containsKey(args.peek()) || isOption(args.peek())) {
2436                         return result;
2437                     }
2438                 }
2439                 consumeOneArgument(field, arity, args, type, result, i, originalSize, argDescription);
2440             }
2441             return result;
2442         }
2443 
2444         private int consumeOneArgument(final Field field,
2445                                        final Range arity,
2446                                        final Stack<String> args,
2447                                        final Class<?> type,
2448                                        final List<Object> result,
2449                                        int index,
2450                                        final int originalSize,
2451                                        final String argDescription) throws Exception {
2452             final String[] values = split(trim(args.pop()), field);
2453             final ITypeConverter<?> converter = getTypeConverter(type, field);
2454 
2455             for (int j = 0; j < values.length; j++) {
2456                 result.add(tryConvert(field, index, converter, values[j], type));
2457                 if (tracer.isInfo()) {
2458                     if (field.getType().isArray()) {
2459                         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);
2460                     } else {
2461                         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);
2462                     }
2463                 }
2464             }
2465             //checkMaxArityExceeded(arity, max, field, values);
2466             return ++index;
2467         }
2468 
2469         private String splitRegex(final Field field) {
2470             if (field.isAnnotationPresent(Option.class))     { return field.getAnnotation(Option.class).split(); }
2471             if (field.isAnnotationPresent(Parameters.class)) { return field.getAnnotation(Parameters.class).split(); }
2472             return "";
2473         }
2474         private String[] split(final String value, final Field field) {
2475             final String regex = splitRegex(field);
2476             return regex.length() == 0 ? new String[] {value} : value.split(regex);
2477         }
2478 
2479         /**
2480          * Called when parsing varargs parameters for a multi-value option.
2481          * When an option is encountered, the remainder should not be interpreted as vararg elements.
2482          * @param arg the string to determine whether it is an option or not
2483          * @return true if it is an option, false otherwise
2484          */
2485         private boolean isOption(final String arg) {
2486             if ("--".equals(arg)) {
2487                 return true;
2488             }
2489             // not just arg prefix: we may be in the middle of parsing -xrvfFILE
2490             if (optionName2Field.containsKey(arg)) { // -v or -f or --file (not attached to param or other option)
2491                 return true;
2492             }
2493             final int separatorIndex = arg.indexOf(separator);
2494             if (separatorIndex > 0) { // -f=FILE or --file==FILE (attached to param via separator)
2495                 if (optionName2Field.containsKey(arg.substring(0, separatorIndex))) {
2496                     return true;
2497                 }
2498             }
2499             return (arg.length() > 2 && arg.startsWith("-") && singleCharOption2Field.containsKey(arg.charAt(1)));
2500         }
2501         private Object tryConvert(final Field field, final int index, final ITypeConverter<?> converter, final String value, final Class<?> type)
2502                 throws Exception {
2503             try {
2504                 return converter.convert(value);
2505             } catch (final TypeConversionException ex) {
2506                 throw new ParameterException(CommandLine.this, ex.getMessage() + optionDescription(" for ", field, index));
2507             } catch (final Exception other) {
2508                 final String desc = optionDescription(" for ", field, index) + ": " + other;
2509                 throw new ParameterException(CommandLine.this, "Could not convert '" + value + "' to " + type.getSimpleName() + desc, other);
2510             }
2511         }
2512 
2513         private String optionDescription(final String prefix, final Field field, final int index) {
2514             final Help.IParamLabelRenderer labelRenderer = Help.createMinimalParamLabelRenderer();
2515             String desc = "";
2516             if (field.isAnnotationPresent(Option.class)) {
2517                 desc = prefix + "option '" + field.getAnnotation(Option.class).names()[0] + "'";
2518                 if (index >= 0) {
2519                     final Range arity = Range.optionArity(field);
2520                     if (arity.max > 1) {
2521                         desc += " at index " + index;
2522                     }
2523                     desc += " (" + labelRenderer.renderParameterLabel(field, Help.Ansi.OFF, Collections.<IStyle>emptyList()) + ")";
2524                 }
2525             } else if (field.isAnnotationPresent(Parameters.class)) {
2526                 final Range indexRange = Range.parameterIndex(field);
2527                 final Text label = labelRenderer.renderParameterLabel(field, Help.Ansi.OFF, Collections.<IStyle>emptyList());
2528                 desc = prefix + "positional parameter at index " + indexRange + " (" + label + ")";
2529             }
2530             return desc;
2531         }
2532 
2533         private boolean isAnyHelpRequested() { return isHelpRequested || versionHelpRequested || usageHelpRequested; }
2534 
2535         private void updateHelpRequested(final Field field) {
2536             if (field.isAnnotationPresent(Option.class)) {
2537                 isHelpRequested                       |= is(field, "help", field.getAnnotation(Option.class).help());
2538                 CommandLine.this.versionHelpRequested |= is(field, "versionHelp", field.getAnnotation(Option.class).versionHelp());
2539                 CommandLine.this.usageHelpRequested   |= is(field, "usageHelp", field.getAnnotation(Option.class).usageHelp());
2540             }
2541         }
2542         private boolean is(final Field f, final String description, final boolean value) {
2543             if (value) { if (tracer.isInfo()) {tracer.info("Field '%s.%s' has '%s' annotation: not validating required fields%n", f.getDeclaringClass().getSimpleName(), f.getName(), description); }}
2544             return value;
2545         }
2546         @SuppressWarnings("unchecked")
2547         private Collection<Object> createCollection(final Class<?> collectionClass) throws Exception {
2548             if (collectionClass.isInterface()) {
2549                 if (List.class.isAssignableFrom(collectionClass)) {
2550                     return new ArrayList<Object>();
2551                 } else if (SortedSet.class.isAssignableFrom(collectionClass)) {
2552                     return new TreeSet<Object>();
2553                 } else if (Set.class.isAssignableFrom(collectionClass)) {
2554                     return new LinkedHashSet<Object>();
2555                 } else if (Queue.class.isAssignableFrom(collectionClass)) {
2556                     return new LinkedList<Object>(); // ArrayDeque is only available since 1.6
2557                 }
2558                 return new ArrayList<Object>();
2559             }
2560             // custom Collection implementation class must have default constructor
2561             return (Collection<Object>) collectionClass.newInstance();
2562         }
2563         private Map<Object, Object> createMap(final Class<?> mapClass) throws Exception {
2564             try { // if it is an implementation class, instantiate it
2565                 return (Map<Object, Object>) mapClass.newInstance();
2566             } catch (final Exception ignored) {}
2567             return new LinkedHashMap<Object, Object>();
2568         }
2569         private ITypeConverter<?> getTypeConverter(final Class<?> type, final Field field) {
2570             final ITypeConverter<?> result = converterRegistry.get(type);
2571             if (result != null) {
2572                 return result;
2573             }
2574             if (type.isEnum()) {
2575                 return new ITypeConverter<Object>() {
2576                     @Override
2577                     @SuppressWarnings("unchecked")
2578                     public Object convert(final String value) throws Exception {
2579                         return Enum.valueOf((Class<Enum>) type, value);
2580                     }
2581                 };
2582             }
2583             throw new MissingTypeConverterException(CommandLine.this, "No TypeConverter registered for " + type.getName() + " of field " + field);
2584         }
2585 
2586         private void assertNoMissingParameters(final Field field, final int arity, final Stack<String> args) {
2587             if (arity > args.size()) {
2588                 if (arity == 1) {
2589                     if (field.isAnnotationPresent(Option.class)) {
2590                         throw new MissingParameterException(CommandLine.this, "Missing required parameter for " +
2591                                 optionDescription("", field, 0));
2592                     }
2593                     final Range indexRange = Range.parameterIndex(field);
2594                     final Help.IParamLabelRenderer labelRenderer = Help.createMinimalParamLabelRenderer();
2595                     String sep = "";
2596                     String names = "";
2597                     int count = 0;
2598                     for (int i = indexRange.min; i < positionalParametersFields.size(); i++) {
2599                         if (Range.parameterArity(positionalParametersFields.get(i)).min > 0) {
2600                             names += sep + labelRenderer.renderParameterLabel(positionalParametersFields.get(i),
2601                                     Help.Ansi.OFF, Collections.<IStyle>emptyList());
2602                             sep = ", ";
2603                             count++;
2604                         }
2605                     }
2606                     String msg = "Missing required parameter";
2607                     final Range paramArity = Range.parameterArity(field);
2608                     if (paramArity.isVariable) {
2609                         msg += "s at positions " + indexRange + ": ";
2610                     } else {
2611                         msg += (count > 1 ? "s: " : ": ");
2612                     }
2613                     throw new MissingParameterException(CommandLine.this, msg + names);
2614                 }
2615                 if (args.isEmpty()) {
2616                     throw new MissingParameterException(CommandLine.this, optionDescription("", field, 0) +
2617                             " requires at least " + arity + " values, but none were specified.");
2618                 }
2619                 throw new MissingParameterException(CommandLine.this, optionDescription("", field, 0) +
2620                         " requires at least " + arity + " values, but only " + args.size() + " were specified: " + reverse(args));
2621             }
2622         }
2623         private String trim(final String value) {
2624             return unquote(value);
2625         }
2626 
2627         private String unquote(final String value) {
2628             return value == null
2629                     ? null
2630                     : (value.length() > 1 && value.startsWith("\"") && value.endsWith("\""))
2631                         ? value.substring(1, value.length() - 1)
2632                         : value;
2633         }
2634     }
2635     private static class PositionalParametersSorter implements Comparator<Field> {
2636         @Override
2637         public int compare(final Field o1, final Field o2) {
2638             final int result = Range.parameterIndex(o1).compareTo(Range.parameterIndex(o2));
2639             return (result == 0) ? Range.parameterArity(o1).compareTo(Range.parameterArity(o2)) : result;
2640         }
2641     }
2642     /**
2643      * Inner class to group the built-in {@link ITypeConverter} implementations.
2644      */
2645     private static class BuiltIn {
2646         static class PathConverter implements ITypeConverter<Path> {
2647             @Override public Path convert(final String value) { return Paths.get(value); }
2648         }
2649         static class StringConverter implements ITypeConverter<String> {
2650             @Override
2651             public String convert(final String value) { return value; }
2652         }
2653         static class StringBuilderConverter implements ITypeConverter<StringBuilder> {
2654             @Override
2655             public StringBuilder convert(final String value) { return new StringBuilder(value); }
2656         }
2657         static class CharSequenceConverter implements ITypeConverter<CharSequence> {
2658             @Override
2659             public String convert(final String value) { return value; }
2660         }
2661         /** Converts text to a {@code Byte} by delegating to {@link Byte#valueOf(String)}.*/
2662         static class ByteConverter implements ITypeConverter<Byte> {
2663             @Override
2664             public Byte convert(final String value) { return Byte.valueOf(value); }
2665         }
2666         /** Converts {@code "true"} or {@code "false"} to a {@code Boolean}. Other values result in a ParameterException.*/
2667         static class BooleanConverter implements ITypeConverter<Boolean> {
2668             @Override
2669             public Boolean convert(final String value) {
2670                 if ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value)) {
2671                     return Boolean.parseBoolean(value);
2672                 } else {
2673                     throw new TypeConversionException("'" + value + "' is not a boolean");
2674                 }
2675             }
2676         }
2677         static class CharacterConverter implements ITypeConverter<Character> {
2678             @Override
2679             public Character convert(final String value) {
2680                 if (value.length() > 1) {
2681                     throw new TypeConversionException("'" + value + "' is not a single character");
2682                 }
2683                 return value.charAt(0);
2684             }
2685         }
2686         /** Converts text to a {@code Short} by delegating to {@link Short#valueOf(String)}.*/
2687         static class ShortConverter implements ITypeConverter<Short> {
2688             @Override
2689             public Short convert(final String value) { return Short.valueOf(value); }
2690         }
2691         /** Converts text to an {@code Integer} by delegating to {@link Integer#valueOf(String)}.*/
2692         static class IntegerConverter implements ITypeConverter<Integer> {
2693             @Override
2694             public Integer convert(final String value) { return Integer.valueOf(value); }
2695         }
2696         /** Converts text to a {@code Long} by delegating to {@link Long#valueOf(String)}.*/
2697         static class LongConverter implements ITypeConverter<Long> {
2698             @Override
2699             public Long convert(final String value) { return Long.valueOf(value); }
2700         }
2701         static class FloatConverter implements ITypeConverter<Float> {
2702             @Override
2703             public Float convert(final String value) { return Float.valueOf(value); }
2704         }
2705         static class DoubleConverter implements ITypeConverter<Double> {
2706             @Override
2707             public Double convert(final String value) { return Double.valueOf(value); }
2708         }
2709         static class FileConverter implements ITypeConverter<File> {
2710             @Override
2711             public File convert(final String value) { return new File(value); }
2712         }
2713         static class URLConverter implements ITypeConverter<URL> {
2714             @Override
2715             public URL convert(final String value) throws MalformedURLException { return new URL(value); }
2716         }
2717         static class URIConverter implements ITypeConverter<URI> {
2718             @Override
2719             public URI convert(final String value) throws URISyntaxException { return new URI(value); }
2720         }
2721         /** Converts text in {@code yyyy-mm-dd} format to a {@code java.util.Date}. ParameterException on failure. */
2722         static class ISO8601DateConverter implements ITypeConverter<Date> {
2723             @Override
2724             public Date convert(final String value) {
2725                 try {
2726                     return new SimpleDateFormat("yyyy-MM-dd").parse(value);
2727                 } catch (final ParseException e) {
2728                     throw new TypeConversionException("'" + value + "' is not a yyyy-MM-dd date");
2729                 }
2730             }
2731         }
2732         /** Converts text in any of the following formats to a {@code java.sql.Time}: {@code HH:mm}, {@code HH:mm:ss},
2733          * {@code HH:mm:ss.SSS}, {@code HH:mm:ss,SSS}. Other formats result in a ParameterException. */
2734         static class ISO8601TimeConverter implements ITypeConverter<Time> {
2735             @Override
2736             public Time convert(final String value) {
2737                 try {
2738                     if (value.length() <= 5) {
2739                         return new Time(new SimpleDateFormat("HH:mm").parse(value).getTime());
2740                     } else if (value.length() <= 8) {
2741                         return new Time(new SimpleDateFormat("HH:mm:ss").parse(value).getTime());
2742                     } else if (value.length() <= 12) {
2743                         try {
2744                             return new Time(new SimpleDateFormat("HH:mm:ss.SSS").parse(value).getTime());
2745                         } catch (final ParseException e2) {
2746                             return new Time(new SimpleDateFormat("HH:mm:ss,SSS").parse(value).getTime());
2747                         }
2748                     }
2749                 } catch (final ParseException ignored) {
2750                     // ignored because we throw a ParameterException below
2751                 }
2752                 throw new TypeConversionException("'" + value + "' is not a HH:mm[:ss[.SSS]] time");
2753             }
2754         }
2755         static class BigDecimalConverter implements ITypeConverter<BigDecimal> {
2756             @Override
2757             public BigDecimal convert(final String value) { return new BigDecimal(value); }
2758         }
2759         static class BigIntegerConverter implements ITypeConverter<BigInteger> {
2760             @Override
2761             public BigInteger convert(final String value) { return new BigInteger(value); }
2762         }
2763         static class CharsetConverter implements ITypeConverter<Charset> {
2764             @Override
2765             public Charset convert(final String s) { return Charset.forName(s); }
2766         }
2767         /** Converts text to a {@code InetAddress} by delegating to {@link InetAddress#getByName(String)}. */
2768         static class InetAddressConverter implements ITypeConverter<InetAddress> {
2769             @Override
2770             public InetAddress convert(final String s) throws Exception { return InetAddress.getByName(s); }
2771         }
2772         static class PatternConverter implements ITypeConverter<Pattern> {
2773             @Override
2774             public Pattern convert(final String s) { return Pattern.compile(s); }
2775         }
2776         static class UUIDConverter implements ITypeConverter<UUID> {
2777             @Override
2778             public UUID convert(final String s) throws Exception { return UUID.fromString(s); }
2779         }
2780         private BuiltIn() {} // private constructor: never instantiate
2781     }
2782 
2783     /**
2784      * A collection of methods and inner classes that provide fine-grained control over the contents and layout of
2785      * the usage help message to display to end users when help is requested or invalid input values were specified.
2786      * <h3>Layered API</h3>
2787      * <p>The {@link Command} annotation provides the easiest way to customize usage help messages. See
2788      * the <a href="https://remkop.github.io/picocli/#_usage_help">Manual</a> for details.</p>
2789      * <p>This Help class provides high-level functions to create sections of the usage help message and headings
2790      * for these sections. Instead of calling the {@link CommandLine#usage(PrintStream, CommandLine.Help.ColorScheme)}
2791      * method, application authors may want to create a custom usage help message by reorganizing sections in a
2792      * different order and/or adding custom sections.</p>
2793      * <p>Finally, the Help class contains inner classes and interfaces that can be used to create custom help messages.</p>
2794      * <h4>IOptionRenderer and IParameterRenderer</h4>
2795      * <p>Renders a field annotated with {@link Option} or {@link Parameters} to an array of {@link Text} values.
2796      * By default, these values are</p><ul>
2797      * <li>mandatory marker character (if the option/parameter is {@link Option#required() required})</li>
2798      * <li>short option name (empty for parameters)</li>
2799      * <li>comma or empty (empty for parameters)</li>
2800      * <li>long option names (the parameter {@link IParamLabelRenderer label} for parameters)</li>
2801      * <li>description</li>
2802      * </ul>
2803      * <p>Other components rely on this ordering.</p>
2804      * <h4>Layout</h4>
2805      * <p>Delegates to the renderers to create {@link Text} values for the annotated fields, and uses a
2806      * {@link TextTable} to display these values in tabular format. Layout is responsible for deciding which values
2807      * to display where in the table. By default, Layout shows one option or parameter per table row.</p>
2808      * <h4>TextTable</h4>
2809      * <p>Responsible for spacing out {@link Text} values according to the {@link Column} definitions the table was
2810      * created with. Columns have a width, indentation, and an overflow policy that decides what to do if a value is
2811      * longer than the column's width.</p>
2812      * <h4>Text</h4>
2813      * <p>Encapsulates rich text with styles and colors in a way that other components like {@link TextTable} are
2814      * unaware of the embedded ANSI escape codes.</p>
2815      */
2816     public static class Help {
2817         /** Constant String holding the default program name: {@value} */
2818         protected static final String DEFAULT_COMMAND_NAME = "<main class>";
2819 
2820         /** Constant String holding the default string that separates options from option parameters: {@value} */
2821         protected static final String DEFAULT_SEPARATOR = "=";
2822 
2823         private final static int usageHelpWidth = 80;
2824         private final static int optionsColumnWidth = 2 + 2 + 1 + 24;
2825         private final Object command;
2826         private final Map<String, Help> commands = new LinkedHashMap<String, Help>();
2827         final ColorScheme colorScheme;
2828 
2829         /** Immutable list of fields annotated with {@link Option}, in declaration order. */
2830         public final List<Field> optionFields;
2831 
2832         /** Immutable list of fields annotated with {@link Parameters}, or an empty list if no such field exists. */
2833         public final List<Field> positionalParametersFields;
2834 
2835         /** The String to use as the separator between options and option parameters. {@code "="} by default,
2836          * initialized from {@link Command#separator()} if defined.
2837          * @see #parameterLabelRenderer */
2838         public String separator;
2839 
2840         /** The String to use as the program name in the synopsis line of the help message.
2841          * {@link #DEFAULT_COMMAND_NAME} by default, initialized from {@link Command#name()} if defined. */
2842         public String commandName = DEFAULT_COMMAND_NAME;
2843 
2844         /** Optional text lines to use as the description of the help message, displayed between the synopsis and the
2845          * options list. Initialized from {@link Command#description()} if the {@code Command} annotation is present,
2846          * otherwise this is an empty array and the help message has no description.
2847          * Applications may programmatically set this field to create a custom help message. */
2848         public String[] description = {};
2849 
2850         /** Optional custom synopsis lines to use instead of the auto-generated synopsis.
2851          * Initialized from {@link Command#customSynopsis()} if the {@code Command} annotation is present,
2852          * otherwise this is an empty array and the synopsis is generated.
2853          * Applications may programmatically set this field to create a custom help message. */
2854         public String[] customSynopsis = {};
2855 
2856         /** Optional header lines displayed at the top of the help message. For subcommands, the first header line is
2857          * displayed in the list of commands. Values are initialized from {@link Command#header()}
2858          * if the {@code Command} annotation is present, otherwise this is an empty array and the help message has no
2859          * header. Applications may programmatically set this field to create a custom help message. */
2860         public String[] header = {};
2861 
2862         /** Optional footer text lines displayed at the bottom of the help message. Initialized from
2863          * {@link Command#footer()} if the {@code Command} annotation is present, otherwise this is an empty array and
2864          * the help message has no footer.
2865          * Applications may programmatically set this field to create a custom help message. */
2866         public String[] footer = {};
2867 
2868         /** Option and positional parameter value label renderer used for the synopsis line(s) and the option list.
2869          * By default initialized to the result of {@link #createDefaultParamLabelRenderer()}, which takes a snapshot
2870          * of the {@link #separator} at construction time. If the separator is modified after Help construction, you
2871          * may need to re-initialize this field by calling {@link #createDefaultParamLabelRenderer()} again. */
2872         public IParamLabelRenderer parameterLabelRenderer;
2873 
2874         /** If {@code true}, the synopsis line(s) will show an abbreviated synopsis without detailed option names. */
2875         public Boolean abbreviateSynopsis;
2876 
2877         /** If {@code true}, the options list is sorted alphabetically. */
2878         public Boolean sortOptions;
2879 
2880         /** If {@code true}, the options list will show default values for all options except booleans. */
2881         public Boolean showDefaultValues;
2882 
2883         /** Character used to prefix required options in the options list. */
2884         public Character requiredOptionMarker;
2885 
2886         /** Optional heading preceding the header section. Initialized from {@link Command#headerHeading()}, or null. */
2887         public String headerHeading;
2888 
2889         /** Optional heading preceding the synopsis. Initialized from {@link Command#synopsisHeading()}, {@code "Usage: "} by default. */
2890         public String synopsisHeading;
2891 
2892         /** Optional heading preceding the description section. Initialized from {@link Command#descriptionHeading()}, or null. */
2893         public String descriptionHeading;
2894 
2895         /** Optional heading preceding the parameter list. Initialized from {@link Command#parameterListHeading()}, or null. */
2896         public String parameterListHeading;
2897 
2898         /** Optional heading preceding the options list. Initialized from {@link Command#optionListHeading()}, or null. */
2899         public String optionListHeading;
2900 
2901         /** Optional heading preceding the subcommand list. Initialized from {@link Command#commandListHeading()}. {@code "Commands:%n"} by default. */
2902         public String commandListHeading;
2903 
2904         /** Optional heading preceding the footer section. Initialized from {@link Command#footerHeading()}, or null. */
2905         public String footerHeading;
2906 
2907         /** Constructs a new {@code Help} instance with a default color scheme, initialized from annotatations
2908          * on the specified class and superclasses.
2909          * @param command the annotated object to create usage help for */
2910         public Help(final Object command) {
2911             this(command, Ansi.AUTO);
2912         }
2913 
2914         /** Constructs a new {@code Help} instance with a default color scheme, initialized from annotatations
2915          * on the specified class and superclasses.
2916          * @param command the annotated object to create usage help for
2917          * @param ansi whether to emit ANSI escape codes or not */
2918         public Help(final Object command, final Ansi ansi) {
2919             this(command, defaultColorScheme(ansi));
2920         }
2921 
2922         /** Constructs a new {@code Help} instance with the specified color scheme, initialized from annotatations
2923          * on the specified class and superclasses.
2924          * @param command the annotated object to create usage help for
2925          * @param colorScheme the color scheme to use */
2926         public Help(final Object command, final ColorScheme colorScheme) {
2927             this.command = Assert.notNull(command, "command");
2928             this.colorScheme = Assert.notNull(colorScheme, "colorScheme").applySystemProperties();
2929             final List<Field> options = new ArrayList<Field>();
2930             final List<Field> operands = new ArrayList<Field>();
2931             Class<?> cls = command.getClass();
2932             while (cls != null) {
2933                 for (final Field field : cls.getDeclaredFields()) {
2934                     field.setAccessible(true);
2935                     if (field.isAnnotationPresent(Option.class)) {
2936                         final Option option = field.getAnnotation(Option.class);
2937                         if (!option.hidden()) { // hidden options should not appear in usage help
2938                             // TODO remember longest concatenated option string length (issue #45)
2939                             options.add(field);
2940                         }
2941                     }
2942                     if (field.isAnnotationPresent(Parameters.class)) {
2943                         operands.add(field);
2944                     }
2945                 }
2946                 // superclass values should not overwrite values if both class and superclass have a @Command annotation
2947                 if (cls.isAnnotationPresent(Command.class)) {
2948                     final Command cmd = cls.getAnnotation(Command.class);
2949                     if (DEFAULT_COMMAND_NAME.equals(commandName)) {
2950                         commandName = cmd.name();
2951                     }
2952                     separator = (separator == null) ? cmd.separator() : separator;
2953                     abbreviateSynopsis = (abbreviateSynopsis == null) ? cmd.abbreviateSynopsis() : abbreviateSynopsis;
2954                     sortOptions = (sortOptions == null) ? cmd.sortOptions() : sortOptions;
2955                     requiredOptionMarker = (requiredOptionMarker == null) ? cmd.requiredOptionMarker() : requiredOptionMarker;
2956                     showDefaultValues = (showDefaultValues == null) ? cmd.showDefaultValues() : showDefaultValues;
2957                     customSynopsis = empty(customSynopsis) ? cmd.customSynopsis() : customSynopsis;
2958                     description = empty(description) ? cmd.description() : description;
2959                     header = empty(header) ? cmd.header() : header;
2960                     footer = empty(footer) ? cmd.footer() : footer;
2961                     headerHeading = empty(headerHeading) ? cmd.headerHeading() : headerHeading;
2962                     synopsisHeading = empty(synopsisHeading) || "Usage: ".equals(synopsisHeading) ? cmd.synopsisHeading() : synopsisHeading;
2963                     descriptionHeading = empty(descriptionHeading) ? cmd.descriptionHeading() : descriptionHeading;
2964                     parameterListHeading = empty(parameterListHeading) ? cmd.parameterListHeading() : parameterListHeading;
2965                     optionListHeading = empty(optionListHeading) ? cmd.optionListHeading() : optionListHeading;
2966                     commandListHeading = empty(commandListHeading) || "Commands:%n".equals(commandListHeading) ? cmd.commandListHeading() : commandListHeading;
2967                     footerHeading = empty(footerHeading) ? cmd.footerHeading() : footerHeading;
2968                 }
2969                 cls = cls.getSuperclass();
2970             }
2971             sortOptions =          (sortOptions == null)          ? true : sortOptions;
2972             abbreviateSynopsis =   (abbreviateSynopsis == null)   ? false : abbreviateSynopsis;
2973             requiredOptionMarker = (requiredOptionMarker == null) ? ' ' : requiredOptionMarker;
2974             showDefaultValues =    (showDefaultValues == null)    ? false : showDefaultValues;
2975             synopsisHeading =      (synopsisHeading == null)      ? "Usage: " : synopsisHeading;
2976             commandListHeading =   (commandListHeading == null)   ? "Commands:%n" : commandListHeading;
2977             separator =            (separator == null)            ? DEFAULT_SEPARATOR : separator;
2978             parameterLabelRenderer = createDefaultParamLabelRenderer(); // uses help separator
2979             Collections.sort(operands, new PositionalParametersSorter());
2980             positionalParametersFields = Collections.unmodifiableList(operands);
2981             optionFields                 = Collections.unmodifiableList(options);
2982         }
2983 
2984         /** Registers all specified subcommands with this Help.
2985          * @param commands maps the command names to the associated CommandLine object
2986          * @return this Help instance (for method chaining)
2987          * @see CommandLine#getSubcommands()
2988          */
2989         public Help addAllSubcommands(final Map<String, CommandLine> commands) {
2990             if (commands != null) {
2991                 for (final Map.Entry<String, CommandLine> entry : commands.entrySet()) {
2992                     addSubcommand(entry.getKey(), entry.getValue().getCommand());
2993                 }
2994             }
2995             return this;
2996         }
2997 
2998         /** Registers the specified subcommand with this Help.
2999          * @param commandName the name of the subcommand to display in the usage message
3000          * @param command the annotated object to get more information from
3001          * @return this Help instance (for method chaining)
3002          */
3003         public Help addSubcommand(final String commandName, final Object command) {
3004             commands.put(commandName, new Help(command));
3005             return this;
3006         }
3007 
3008         /** Returns a synopsis for the command without reserving space for the synopsis heading.
3009          * @return a synopsis
3010          * @see #abbreviatedSynopsis()
3011          * @see #detailedSynopsis(Comparator, boolean)
3012          * @deprecated use {@link #synopsis(int)} instead
3013          */
3014         @Deprecated
3015         public String synopsis() { return synopsis(0); }
3016 
3017         /**
3018          * Returns a synopsis for the command, reserving the specified space for the synopsis heading.
3019          * @param synopsisHeadingLength the length of the synopsis heading that will be displayed on the same line
3020          * @return a synopsis
3021          * @see #abbreviatedSynopsis()
3022          * @see #detailedSynopsis(Comparator, boolean)
3023          * @see #synopsisHeading
3024          */
3025         public String synopsis(final int synopsisHeadingLength) {
3026             if (!empty(customSynopsis)) { return customSynopsis(); }
3027             return abbreviateSynopsis ? abbreviatedSynopsis()
3028                     : detailedSynopsis(synopsisHeadingLength, createShortOptionArityAndNameComparator(), true);
3029         }
3030 
3031         /** Generates a generic synopsis like {@code <command name> [OPTIONS] [PARAM1 [PARAM2]...]}, omitting parts
3032          * that don't apply to the command (e.g., does not show [OPTIONS] if the command has no options).
3033          * @return a generic synopsis */
3034         public String abbreviatedSynopsis() {
3035             final StringBuilder sb = new StringBuilder();
3036             if (!optionFields.isEmpty()) { // only show if annotated object actually has options
3037                 sb.append(" [OPTIONS]");
3038             }
3039             // sb.append(" [--] "); // implied
3040             for (final Field positionalParam : positionalParametersFields) {
3041                 if (!positionalParam.getAnnotation(Parameters.class).hidden()) {
3042                     sb.append(' ').append(parameterLabelRenderer.renderParameterLabel(positionalParam, ansi(), colorScheme.parameterStyles));
3043                 }
3044             }
3045             return colorScheme.commandText(commandName).toString()
3046                     + (sb.toString()) + System.getProperty("line.separator");
3047         }
3048         /** Generates a detailed synopsis message showing all options and parameters. Follows the unix convention of
3049          * showing optional options and parameters in square brackets ({@code [ ]}).
3050          * @param optionSort comparator to sort options or {@code null} if options should not be sorted
3051          * @param clusterBooleanOptions {@code true} if boolean short options should be clustered into a single string
3052          * @return a detailed synopsis
3053          * @deprecated use {@link #detailedSynopsis(int, Comparator, boolean)} instead. */
3054         @Deprecated
3055         public String detailedSynopsis(final Comparator<Field> optionSort, final boolean clusterBooleanOptions) {
3056             return detailedSynopsis(0, optionSort, clusterBooleanOptions);
3057         }
3058 
3059         /** Generates a detailed synopsis message showing all options and parameters. Follows the unix convention of
3060          * showing optional options and parameters in square brackets ({@code [ ]}).
3061          * @param synopsisHeadingLength the length of the synopsis heading that will be displayed on the same line
3062          * @param optionSort comparator to sort options or {@code null} if options should not be sorted
3063          * @param clusterBooleanOptions {@code true} if boolean short options should be clustered into a single string
3064          * @return a detailed synopsis */
3065         public String detailedSynopsis(final int synopsisHeadingLength, final Comparator<Field> optionSort, final boolean clusterBooleanOptions) {
3066             Text optionText = ansi().new Text(0);
3067             final List<Field> fields = new ArrayList<Field>(optionFields); // iterate in declaration order
3068             if (optionSort != null) {
3069                 Collections.sort(fields, optionSort);// iterate in specified sort order
3070             }
3071             if (clusterBooleanOptions) { // cluster all short boolean options into a single string
3072                 final List<Field> booleanOptions = new ArrayList<Field>();
3073                 final StringBuilder clusteredRequired = new StringBuilder("-");
3074                 final StringBuilder clusteredOptional = new StringBuilder("-");
3075                 for (final Field field : fields) {
3076                     if (field.getType() == boolean.class || field.getType() == Boolean.class) {
3077                         final Option option = field.getAnnotation(Option.class);
3078                         final String shortestName = ShortestFirst.sort(option.names())[0];
3079                         if (shortestName.length() == 2 && shortestName.startsWith("-")) {
3080                             booleanOptions.add(field);
3081                             if (option.required()) {
3082                                 clusteredRequired.append(shortestName.substring(1));
3083                             } else {
3084                                 clusteredOptional.append(shortestName.substring(1));
3085                             }
3086                         }
3087                     }
3088                 }
3089                 fields.removeAll(booleanOptions);
3090                 if (clusteredRequired.length() > 1) { // initial length was 1
3091                     optionText = optionText.append(" ").append(colorScheme.optionText(clusteredRequired.toString()));
3092                 }
3093                 if (clusteredOptional.length() > 1) { // initial length was 1
3094                     optionText = optionText.append(" [").append(colorScheme.optionText(clusteredOptional.toString())).append("]");
3095                 }
3096             }
3097             for (final Field field : fields) {
3098                 final Option option = field.getAnnotation(Option.class);
3099                 if (!option.hidden()) {
3100                     if (option.required()) {
3101                         optionText = appendOptionSynopsis(optionText, field, ShortestFirst.sort(option.names())[0], " ", "");
3102                         if (isMultiValue(field)) {
3103                             optionText = appendOptionSynopsis(optionText, field, ShortestFirst.sort(option.names())[0], " [", "]...");
3104                         }
3105                     } else {
3106                         optionText = appendOptionSynopsis(optionText, field, ShortestFirst.sort(option.names())[0], " [", "]");
3107                         if (isMultiValue(field)) {
3108                             optionText = optionText.append("...");
3109                         }
3110                     }
3111                 }
3112             }
3113             for (final Field positionalParam : positionalParametersFields) {
3114                 if (!positionalParam.getAnnotation(Parameters.class).hidden()) {
3115                     optionText = optionText.append(" ");
3116                     final Text label = parameterLabelRenderer.renderParameterLabel(positionalParam, colorScheme.ansi(), colorScheme.parameterStyles);
3117                     optionText = optionText.append(label);
3118                 }
3119             }
3120             // Fix for #142: first line of synopsis overshoots max. characters
3121             final int firstColumnLength = commandName.length() + synopsisHeadingLength;
3122 
3123             // synopsis heading ("Usage: ") may be on the same line, so adjust column width
3124             final TextTable textTable = new TextTable(ansi(), firstColumnLength, usageHelpWidth - firstColumnLength);
3125             textTable.indentWrappedLines = 1; // don't worry about first line: options (2nd column) always start with a space
3126 
3127             // right-adjust the command name by length of synopsis heading
3128             final Text PADDING = Ansi.OFF.new Text(stringOf('X', synopsisHeadingLength));
3129             textTable.addRowValues(new Text[] {PADDING.append(colorScheme.commandText(commandName)), optionText});
3130             return textTable.toString().substring(synopsisHeadingLength); // cut off leading synopsis heading spaces
3131         }
3132 
3133         private Text appendOptionSynopsis(final Text optionText, final Field field, final String optionName, final String prefix, final String suffix) {
3134             final Text optionParamText = parameterLabelRenderer.renderParameterLabel(field, colorScheme.ansi(), colorScheme.optionParamStyles);
3135             return optionText.append(prefix)
3136                     .append(colorScheme.optionText(optionName))
3137                     .append(optionParamText)
3138                     .append(suffix);
3139         }
3140 
3141         /** Returns the number of characters the synopsis heading will take on the same line as the synopsis.
3142          * @return the number of characters the synopsis heading will take on the same line as the synopsis.
3143          * @see #detailedSynopsis(int, Comparator, boolean)
3144          */
3145         public int synopsisHeadingLength() {
3146             final String[] lines = Ansi.OFF.new Text(synopsisHeading).toString().split("\\r?\\n|\\r|%n", -1);
3147             return lines[lines.length - 1].length();
3148         }
3149         /**
3150          * <p>Returns a description of the {@linkplain Option options} supported by the application.
3151          * This implementation {@linkplain #createShortOptionNameComparator() sorts options alphabetically}, and shows
3152          * only the {@linkplain Option#hidden() non-hidden} options in a {@linkplain TextTable tabular format}
3153          * using the {@linkplain #createDefaultOptionRenderer() default renderer} and {@linkplain Layout default layout}.</p>
3154          * @return the fully formatted option list
3155          * @see #optionList(Layout, Comparator, IParamLabelRenderer)
3156          */
3157         public String optionList() {
3158             final Comparator<Field> sortOrder = sortOptions == null || sortOptions.booleanValue()
3159                     ? createShortOptionNameComparator()
3160                     : null;
3161             return optionList(createDefaultLayout(), sortOrder, parameterLabelRenderer);
3162         }
3163 
3164         /** Sorts all {@code Options} with the specified {@code comparator} (if the comparator is non-{@code null}),
3165          * then {@linkplain Layout#addOption(Field, CommandLine.Help.IParamLabelRenderer) adds} all non-hidden options to the
3166          * specified TextTable and returns the result of TextTable.toString().
3167          * @param layout responsible for rendering the option list
3168          * @param optionSort determines in what order {@code Options} should be listed. Declared order if {@code null}
3169          * @param valueLabelRenderer used for options with a parameter
3170          * @return the fully formatted option list
3171          */
3172         public String optionList(final Layout layout, final Comparator<Field> optionSort, final IParamLabelRenderer valueLabelRenderer) {
3173             final List<Field> fields = new ArrayList<Field>(optionFields); // options are stored in order of declaration
3174             if (optionSort != null) {
3175                 Collections.sort(fields, optionSort); // default: sort options ABC
3176             }
3177             layout.addOptions(fields, valueLabelRenderer);
3178             return layout.toString();
3179         }
3180 
3181         /**
3182          * Returns the section of the usage help message that lists the parameters with their descriptions.
3183          * @return the section of the usage help message that lists the parameters
3184          */
3185         public String parameterList() {
3186             return parameterList(createDefaultLayout(), parameterLabelRenderer);
3187         }
3188         /**
3189          * Returns the section of the usage help message that lists the parameters with their descriptions.
3190          * @param layout the layout to use
3191          * @param paramLabelRenderer for rendering parameter names
3192          * @return the section of the usage help message that lists the parameters
3193          */
3194         public String parameterList(final Layout layout, final IParamLabelRenderer paramLabelRenderer) {
3195             layout.addPositionalParameters(positionalParametersFields, paramLabelRenderer);
3196             return layout.toString();
3197         }
3198 
3199         private static String heading(final Ansi ansi, final String values, final Object... params) {
3200             final StringBuilder sb = join(ansi, new String[] {values}, new StringBuilder(), params);
3201             String result = sb.toString();
3202             result = result.endsWith(System.getProperty("line.separator"))
3203                     ? result.substring(0, result.length() - System.getProperty("line.separator").length()) : result;
3204             return result + new String(spaces(countTrailingSpaces(values)));
3205         }
3206         private static char[] spaces(final int length) { final char[] result = new char[length]; Arrays.fill(result, ' '); return result; }
3207         private static int countTrailingSpaces(final String str) {
3208             if (str == null) {return 0;}
3209             int trailingSpaces = 0;
3210             for (int i = str.length() - 1; i >= 0 && str.charAt(i) == ' '; i--) { trailingSpaces++; }
3211             return trailingSpaces;
3212         }
3213 
3214         /** Formats each of the specified values and appends it to the specified StringBuilder.
3215          * @param ansi whether the result should contain ANSI escape codes or not
3216          * @param values the values to format and append to the StringBuilder
3217          * @param sb the StringBuilder to collect the formatted strings
3218          * @param params the parameters to pass to the format method when formatting each value
3219          * @return the specified StringBuilder */
3220         public static StringBuilder join(final Ansi ansi, final String[] values, final StringBuilder sb, final Object... params) {
3221             if (values != null) {
3222                 final TextTable table = new TextTable(ansi, usageHelpWidth);
3223                 table.indentWrappedLines = 0;
3224                 for (final String summaryLine : values) {
3225                     final Text[] lines = ansi.new Text(format(summaryLine, params)).splitLines();
3226                     for (final Text line : lines) {  table.addRowValues(line); }
3227                 }
3228                 table.toString(sb);
3229             }
3230             return sb;
3231         }
3232         private static String format(final String formatString,  final Object... params) {
3233             return formatString == null ? "" : String.format(formatString, params);
3234         }
3235         /** Returns command custom synopsis as a string. A custom synopsis can be zero or more lines, and can be
3236          * specified declaratively with the {@link Command#customSynopsis()} annotation attribute or programmatically
3237          * by setting the Help instance's {@link Help#customSynopsis} field.
3238          * @param params Arguments referenced by the format specifiers in the synopsis strings
3239          * @return the custom synopsis lines combined into a single String (which may be empty)
3240          */
3241         public String customSynopsis(final Object... params) {
3242             return join(ansi(), customSynopsis, new StringBuilder(), params).toString();
3243         }
3244         /** Returns command description text as a string. Description text can be zero or more lines, and can be specified
3245          * declaratively with the {@link Command#description()} annotation attribute or programmatically by
3246          * setting the Help instance's {@link Help#description} field.
3247          * @param params Arguments referenced by the format specifiers in the description strings
3248          * @return the description lines combined into a single String (which may be empty)
3249          */
3250         public String description(final Object... params) {
3251             return join(ansi(), description, new StringBuilder(), params).toString();
3252         }
3253         /** Returns the command header text as a string. Header text can be zero or more lines, and can be specified
3254          * declaratively with the {@link Command#header()} annotation attribute or programmatically by
3255          * setting the Help instance's {@link Help#header} field.
3256          * @param params Arguments referenced by the format specifiers in the header strings
3257          * @return the header lines combined into a single String (which may be empty)
3258          */
3259         public String header(final Object... params) {
3260             return join(ansi(), header, new StringBuilder(), params).toString();
3261         }
3262         /** Returns command footer text as a string. Footer text can be zero or more lines, and can be specified
3263          * declaratively with the {@link Command#footer()} annotation attribute or programmatically by
3264          * setting the Help instance's {@link Help#footer} field.
3265          * @param params Arguments referenced by the format specifiers in the footer strings
3266          * @return the footer lines combined into a single String (which may be empty)
3267          */
3268         public String footer(final Object... params) {
3269             return join(ansi(), footer, new StringBuilder(), params).toString();
3270         }
3271 
3272         /** Returns the text displayed before the header text; the result of {@code String.format(headerHeading, params)}.
3273          * @param params the parameters to use to format the header heading
3274          * @return the formatted header heading */
3275         public String headerHeading(final Object... params) {
3276             return heading(ansi(), headerHeading, params);
3277         }
3278 
3279         /** Returns the text displayed before the synopsis text; the result of {@code String.format(synopsisHeading, params)}.
3280          * @param params the parameters to use to format the synopsis heading
3281          * @return the formatted synopsis heading */
3282         public String synopsisHeading(final Object... params) {
3283             return heading(ansi(), synopsisHeading, params);
3284         }
3285 
3286         /** Returns the text displayed before the description text; an empty string if there is no description,
3287          * otherwise the result of {@code String.format(descriptionHeading, params)}.
3288          * @param params the parameters to use to format the description heading
3289          * @return the formatted description heading */
3290         public String descriptionHeading(final Object... params) {
3291             return empty(descriptionHeading) ? "" : heading(ansi(), descriptionHeading, params);
3292         }
3293 
3294         /** Returns the text displayed before the positional parameter list; an empty string if there are no positional
3295          * parameters, otherwise the result of {@code String.format(parameterListHeading, params)}.
3296          * @param params the parameters to use to format the parameter list heading
3297          * @return the formatted parameter list heading */
3298         public String parameterListHeading(final Object... params) {
3299             return positionalParametersFields.isEmpty() ? "" : heading(ansi(), parameterListHeading, params);
3300         }
3301 
3302         /** Returns the text displayed before the option list; an empty string if there are no options,
3303          * otherwise the result of {@code String.format(optionListHeading, params)}.
3304          * @param params the parameters to use to format the option list heading
3305          * @return the formatted option list heading */
3306         public String optionListHeading(final Object... params) {
3307             return optionFields.isEmpty() ? "" : heading(ansi(), optionListHeading, params);
3308         }
3309 
3310         /** Returns the text displayed before the command list; an empty string if there are no commands,
3311          * otherwise the result of {@code String.format(commandListHeading, params)}.
3312          * @param params the parameters to use to format the command list heading
3313          * @return the formatted command list heading */
3314         public String commandListHeading(final Object... params) {
3315             return commands.isEmpty() ? "" : heading(ansi(), commandListHeading, params);
3316         }
3317 
3318         /** Returns the text displayed before the footer text; the result of {@code String.format(footerHeading, params)}.
3319          * @param params the parameters to use to format the footer heading
3320          * @return the formatted footer heading */
3321         public String footerHeading(final Object... params) {
3322             return heading(ansi(), footerHeading, params);
3323         }
3324         /** Returns a 2-column list with command names and the first line of their header or (if absent) description.
3325          * @return a usage help section describing the added commands */
3326         public String commandList() {
3327             if (commands.isEmpty()) { return ""; }
3328             final int commandLength = maxLength(commands.keySet());
3329             final Help.TextTable textTable = new Help.TextTable(ansi(),
3330                     new Help.Column(commandLength + 2, 2, Help.Column.Overflow.SPAN),
3331                     new Help.Column(usageHelpWidth - (commandLength + 2), 2, Help.Column.Overflow.WRAP));
3332 
3333             for (final Map.Entry<String, Help> entry : commands.entrySet()) {
3334                 final Help command = entry.getValue();
3335                 final String header = command.header != null && command.header.length > 0 ? command.header[0]
3336                         : (command.description != null && command.description.length > 0 ? command.description[0] : "");
3337                 textTable.addRowValues(colorScheme.commandText(entry.getKey()), ansi().new Text(header));
3338             }
3339             return textTable.toString();
3340         }
3341         private static int maxLength(final Collection<String> any) {
3342             final List<String> strings = new ArrayList<String>(any);
3343             Collections.sort(strings, Collections.reverseOrder(Help.shortestFirst()));
3344             return strings.get(0).length();
3345         }
3346         private static String join(final String[] names, final int offset, final int length, final String separator) {
3347             if (names == null) { return ""; }
3348             final StringBuilder result = new StringBuilder();
3349             for (int i = offset; i < offset + length; i++) {
3350                 result.append((i > offset) ? separator : "").append(names[i]);
3351             }
3352             return result.toString();
3353         }
3354         private static String stringOf(final char chr, final int length) {
3355             final char[] buff = new char[length];
3356             Arrays.fill(buff, chr);
3357             return new String(buff);
3358         }
3359 
3360         /** Returns a {@code Layout} instance configured with the user preferences captured in this Help instance.
3361          * @return a Layout */
3362         public Layout createDefaultLayout() {
3363             return new Layout(colorScheme, new TextTable(colorScheme.ansi()), createDefaultOptionRenderer(), createDefaultParameterRenderer());
3364         }
3365         /** Returns a new default OptionRenderer which converts {@link Option Options} to five columns of text to match
3366          *  the default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
3367          * <ol>
3368          * <li>the required option marker</li>
3369          * <li>2-character short option name (or empty string if no short option exists)</li>
3370          * <li>comma separator (only if both short option and long option exist, empty string otherwise)</li>
3371          * <li>comma-separated string with long option name(s)</li>
3372          * <li>first element of the {@link Option#description()} array</li>
3373          * </ol>
3374          * <p>Following this, there will be one row for each of the remaining elements of the {@link
3375          *   Option#description()} array, and these rows look like {@code {"", "", "", "", option.description()[i]}}.</p>
3376          * <p>If configured, this option renderer adds an additional row to display the default field value.</p>
3377          * @return a new default OptionRenderer
3378          */
3379         public IOptionRenderer createDefaultOptionRenderer() {
3380             final DefaultOptionRenderer result = new DefaultOptionRenderer();
3381             result.requiredMarker = String.valueOf(requiredOptionMarker);
3382             if (showDefaultValues != null && showDefaultValues.booleanValue()) {
3383                 result.command = this.command;
3384             }
3385             return result;
3386         }
3387         /** Returns a new minimal OptionRenderer which converts {@link Option Options} to a single row with two columns
3388          * of text: an option name and a description. If multiple names or descriptions exist, the first value is used.
3389          * @return a new minimal OptionRenderer */
3390         public static IOptionRenderer createMinimalOptionRenderer() {
3391             return new MinimalOptionRenderer();
3392         }
3393 
3394         /** Returns a new default ParameterRenderer which converts {@link Parameters Parameters} to four columns of
3395          * text to match the default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
3396          * <ol>
3397          * <li>empty string </li>
3398          * <li>empty string </li>
3399          * <li>parameter(s) label as rendered by the {@link IParamLabelRenderer}</li>
3400          * <li>first element of the {@link Parameters#description()} array</li>
3401          * </ol>
3402          * <p>Following this, there will be one row for each of the remaining elements of the {@link
3403          *   Parameters#description()} array, and these rows look like {@code {"", "", "", param.description()[i]}}.</p>
3404          * <p>If configured, this parameter renderer adds an additional row to display the default field value.</p>
3405          * @return a new default ParameterRenderer
3406          */
3407         public IParameterRenderer createDefaultParameterRenderer() {
3408             final DefaultParameterRenderer result = new DefaultParameterRenderer();
3409             result.requiredMarker = String.valueOf(requiredOptionMarker);
3410             return result;
3411         }
3412         /** Returns a new minimal ParameterRenderer which converts {@link Parameters Parameters} to a single row with
3413          * two columns of text: an option name and a description. If multiple descriptions exist, the first value is used.
3414          * @return a new minimal ParameterRenderer */
3415         public static IParameterRenderer createMinimalParameterRenderer() {
3416             return new MinimalParameterRenderer();
3417         }
3418 
3419         /** Returns a value renderer that returns the {@code paramLabel} if defined or the field name otherwise.
3420          * @return a new minimal ParamLabelRenderer */
3421         public static IParamLabelRenderer createMinimalParamLabelRenderer() {
3422             return new IParamLabelRenderer() {
3423                 @Override
3424                 public Text renderParameterLabel(final Field field, final Ansi ansi, final List<IStyle> styles) {
3425                     final String text = DefaultParamLabelRenderer.renderParameterName(field);
3426                     return ansi.apply(text, styles);
3427                 }
3428                 @Override
3429                 public String separator() { return ""; }
3430             };
3431         }
3432         /** Returns a new default value renderer that separates option parameters from their {@linkplain Option
3433          * options} with the specified separator string, surrounds optional parameters with {@code '['} and {@code ']'}
3434          * characters and uses ellipses ("...") to indicate that any number of a parameter are allowed.
3435          * @return a new default ParamLabelRenderer
3436          */
3437         public IParamLabelRenderer createDefaultParamLabelRenderer() {
3438             return new DefaultParamLabelRenderer(separator);
3439         }
3440         /** Sorts Fields annotated with {@code Option} by their option name in case-insensitive alphabetic order. If an
3441          * Option has multiple names, the shortest name is used for the sorting. Help options follow non-help options.
3442          * @return a comparator that sorts fields by their option name in case-insensitive alphabetic order */
3443         public static Comparator<Field> createShortOptionNameComparator() {
3444             return new SortByShortestOptionNameAlphabetically();
3445         }
3446         /** Sorts Fields annotated with {@code Option} by their option {@linkplain Range#max max arity} first, by
3447          * {@linkplain Range#min min arity} next, and by {@linkplain #createShortOptionNameComparator() option name} last.
3448          * @return a comparator that sorts fields by arity first, then their option name */
3449         public static Comparator<Field> createShortOptionArityAndNameComparator() {
3450             return new SortByOptionArityAndNameAlphabetically();
3451         }
3452         /** Sorts short strings before longer strings.
3453          * @return a comparators that sorts short strings before longer strings */
3454         public static Comparator<String> shortestFirst() {
3455             return new ShortestFirst();
3456         }
3457 
3458         /** Returns whether ANSI escape codes are enabled or not.
3459          * @return whether ANSI escape codes are enabled or not
3460          */
3461         public Ansi ansi() {
3462             return colorScheme.ansi;
3463         }
3464 
3465         /** When customizing online help for {@link Option Option} details, a custom {@code IOptionRenderer} can be
3466          * used to create textual representation of an Option in a tabular format: one or more rows, each containing
3467          * one or more columns. The {@link Layout Layout} is responsible for placing these text values in the
3468          * {@link TextTable TextTable}. */
3469         public interface IOptionRenderer {
3470             /**
3471              * Returns a text representation of the specified Option and the Field that captures the option value.
3472              * @param option the command line option to show online usage help for
3473              * @param field the field that will hold the value for the command line option
3474              * @param parameterLabelRenderer responsible for rendering option parameters to text
3475              * @param scheme color scheme for applying ansi color styles to options and option parameters
3476              * @return a 2-dimensional array of text values: one or more rows, each containing one or more columns
3477              */
3478             Text[][] render(Option option, Field field, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme);
3479         }
3480         /** The DefaultOptionRenderer converts {@link Option Options} to five columns of text to match the default
3481          * {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
3482          * <ol>
3483          * <li>the required option marker (if the option is required)</li>
3484          * <li>2-character short option name (or empty string if no short option exists)</li>
3485          * <li>comma separator (only if both short option and long option exist, empty string otherwise)</li>
3486          * <li>comma-separated string with long option name(s)</li>
3487          * <li>first element of the {@link Option#description()} array</li>
3488          * </ol>
3489          * <p>Following this, there will be one row for each of the remaining elements of the {@link
3490          *   Option#description()} array, and these rows look like {@code {"", "", "", option.description()[i]}}.</p>
3491          */
3492         static class DefaultOptionRenderer implements IOptionRenderer {
3493             public String requiredMarker = " ";
3494             public Object command;
3495             private String sep;
3496             private boolean showDefault;
3497             @Override
3498             public Text[][] render(final Option option, final Field field, final IParamLabelRenderer paramLabelRenderer, final ColorScheme scheme) {
3499                 final String[] names = ShortestFirst.sort(option.names());
3500                 final int shortOptionCount = names[0].length() == 2 ? 1 : 0;
3501                 final String shortOption = shortOptionCount > 0 ? names[0] : "";
3502                 sep = shortOptionCount > 0 && names.length > 1 ? "," : "";
3503 
3504                 final String longOption = join(names, shortOptionCount, names.length - shortOptionCount, ", ");
3505                 final Text longOptionText = createLongOptionText(field, paramLabelRenderer, scheme, longOption);
3506 
3507                 showDefault = command != null && !option.help() && !isBoolean(field.getType());
3508                 final Object defaultValue = createDefaultValue(field);
3509 
3510                 final String requiredOption = option.required() ? requiredMarker : "";
3511                 return renderDescriptionLines(option, scheme, requiredOption, shortOption, longOptionText, defaultValue);
3512             }
3513 
3514             private Object createDefaultValue(final Field field) {
3515                 Object defaultValue = null;
3516                 try {
3517                     defaultValue = field.get(command);
3518                     if (defaultValue == null) { showDefault = false; } // #201 don't show null default values
3519                     else if (field.getType().isArray()) {
3520                         final StringBuilder sb = new StringBuilder();
3521                         for (int i = 0; i < Array.getLength(defaultValue); i++) {
3522                             sb.append(i > 0 ? ", " : "").append(Array.get(defaultValue, i));
3523                         }
3524                         defaultValue = sb.insert(0, "[").append("]").toString();
3525                     }
3526                 } catch (final Exception ex) {
3527                     showDefault = false;
3528                 }
3529                 return defaultValue;
3530             }
3531 
3532             private Text createLongOptionText(final Field field, final IParamLabelRenderer renderer, final ColorScheme scheme, final String longOption) {
3533                 Text paramLabelText = renderer.renderParameterLabel(field, scheme.ansi(), scheme.optionParamStyles);
3534 
3535                 // if no long option, fill in the space between the short option name and the param label value
3536                 if (paramLabelText.length > 0 && longOption.length() == 0) {
3537                     sep = renderer.separator();
3538                     // #181 paramLabelText may be =LABEL or [=LABEL...]
3539                     final int sepStart = paramLabelText.plainString().indexOf(sep);
3540                     final Text prefix = paramLabelText.substring(0, sepStart);
3541                     paramLabelText = prefix.append(paramLabelText.substring(sepStart + sep.length()));
3542                 }
3543                 Text longOptionText = scheme.optionText(longOption);
3544                 longOptionText = longOptionText.append(paramLabelText);
3545                 return longOptionText;
3546             }
3547 
3548             private Text[][] renderDescriptionLines(final Option option,
3549                                                     final ColorScheme scheme,
3550                                                     final String requiredOption,
3551                                                     final String shortOption,
3552                                                     final Text longOptionText,
3553                                                     final Object defaultValue) {
3554                 final Text EMPTY = Ansi.EMPTY_TEXT;
3555                 final List<Text[]> result = new ArrayList<Text[]>();
3556                 Text[] descriptionFirstLines = scheme.ansi().new Text(str(option.description(), 0)).splitLines();
3557                 if (descriptionFirstLines.length == 0) {
3558                     if (showDefault) {
3559                         descriptionFirstLines = new Text[]{scheme.ansi().new Text("  Default: " + defaultValue)};
3560                         showDefault = false; // don't show the default value twice
3561                     } else {
3562                         descriptionFirstLines = new Text[]{ EMPTY };
3563                     }
3564                 }
3565                 result.add(new Text[] { scheme.optionText(requiredOption), scheme.optionText(shortOption),
3566                         scheme.ansi().new Text(sep), longOptionText, descriptionFirstLines[0] });
3567                 for (int i = 1; i < descriptionFirstLines.length; i++) {
3568                     result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, descriptionFirstLines[i] });
3569                 }
3570                 for (int i = 1; i < option.description().length; i++) {
3571                     final Text[] descriptionNextLines = scheme.ansi().new Text(option.description()[i]).splitLines();
3572                     for (final Text line : descriptionNextLines) {
3573                         result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, line });
3574                     }
3575                 }
3576                 if (showDefault) {
3577                     result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, scheme.ansi().new Text("  Default: " + defaultValue) });
3578                 }
3579                 return result.toArray(new Text[result.size()][]);
3580             }
3581         }
3582         /** The MinimalOptionRenderer converts {@link Option Options} to a single row with two columns of text: an
3583          * option name and a description. If multiple names or description lines exist, the first value is used. */
3584         static class MinimalOptionRenderer implements IOptionRenderer {
3585             @Override
3586             public Text[][] render(final Option option, final Field field, final IParamLabelRenderer parameterLabelRenderer, final ColorScheme scheme) {
3587                 Text optionText = scheme.optionText(option.names()[0]);
3588                 final Text paramLabelText = parameterLabelRenderer.renderParameterLabel(field, scheme.ansi(), scheme.optionParamStyles);
3589                 optionText = optionText.append(paramLabelText);
3590                 return new Text[][] {{ optionText,
3591                                         scheme.ansi().new Text(option.description().length == 0 ? "" : option.description()[0]) }};
3592             }
3593         }
3594         /** The MinimalParameterRenderer converts {@link Parameters Parameters} to a single row with two columns of
3595          * text: the parameters label and a description. If multiple description lines exist, the first value is used. */
3596         static class MinimalParameterRenderer implements IParameterRenderer {
3597             @Override
3598             public Text[][] render(final Parameters param, final Field field, final IParamLabelRenderer parameterLabelRenderer, final ColorScheme scheme) {
3599                 return new Text[][] {{ parameterLabelRenderer.renderParameterLabel(field, scheme.ansi(), scheme.parameterStyles),
3600                         scheme.ansi().new Text(param.description().length == 0 ? "" : param.description()[0]) }};
3601             }
3602         }
3603         /** When customizing online help for {@link Parameters Parameters} details, a custom {@code IParameterRenderer}
3604          * can be used to create textual representation of a Parameters field in a tabular format: one or more rows,
3605          * each containing one or more columns. The {@link Layout Layout} is responsible for placing these text
3606          * values in the {@link TextTable TextTable}. */
3607         public interface IParameterRenderer {
3608             /**
3609              * Returns a text representation of the specified Parameters and the Field that captures the parameter values.
3610              * @param parameters the command line parameters to show online usage help for
3611              * @param field the field that will hold the value for the command line parameters
3612              * @param parameterLabelRenderer responsible for rendering parameter labels to text
3613              * @param scheme color scheme for applying ansi color styles to positional parameters
3614              * @return a 2-dimensional array of text values: one or more rows, each containing one or more columns
3615              */
3616             Text[][] render(Parameters parameters, Field field, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme);
3617         }
3618         /** The DefaultParameterRenderer converts {@link Parameters Parameters} to five columns of text to match the
3619          * default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
3620          * <ol>
3621          * <li>the required option marker (if the parameter's arity is to have at least one value)</li>
3622          * <li>empty string </li>
3623          * <li>empty string </li>
3624          * <li>parameter(s) label as rendered by the {@link IParamLabelRenderer}</li>
3625          * <li>first element of the {@link Parameters#description()} array</li>
3626          * </ol>
3627          * <p>Following this, there will be one row for each of the remaining elements of the {@link
3628          *   Parameters#description()} array, and these rows look like {@code {"", "", "", param.description()[i]}}.</p>
3629          */
3630         static class DefaultParameterRenderer implements IParameterRenderer {
3631             public String requiredMarker = " ";
3632             @Override
3633             public Text[][] render(final Parameters params, final Field field, final IParamLabelRenderer paramLabelRenderer, final ColorScheme scheme) {
3634                 final Text label = paramLabelRenderer.renderParameterLabel(field, scheme.ansi(), scheme.parameterStyles);
3635                 final Text requiredParameter = scheme.parameterText(Range.parameterArity(field).min > 0 ? requiredMarker : "");
3636 
3637                 final Text EMPTY = Ansi.EMPTY_TEXT;
3638                 final List<Text[]> result = new ArrayList<Text[]>();
3639                 Text[] descriptionFirstLines = scheme.ansi().new Text(str(params.description(), 0)).splitLines();
3640                 if (descriptionFirstLines.length == 0) { descriptionFirstLines = new Text[]{ EMPTY }; }
3641                 result.add(new Text[] { requiredParameter, EMPTY, EMPTY, label, descriptionFirstLines[0] });
3642                 for (int i = 1; i < descriptionFirstLines.length; i++) {
3643                     result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, descriptionFirstLines[i] });
3644                 }
3645                 for (int i = 1; i < params.description().length; i++) {
3646                     final Text[] descriptionNextLines = scheme.ansi().new Text(params.description()[i]).splitLines();
3647                     for (final Text line : descriptionNextLines) {
3648                         result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, line });
3649                     }
3650                 }
3651                 return result.toArray(new Text[result.size()][]);
3652             }
3653         }
3654         /** When customizing online usage help for an option parameter or a positional parameter, a custom
3655          * {@code IParamLabelRenderer} can be used to render the parameter name or label to a String. */
3656         public interface IParamLabelRenderer {
3657 
3658             /** Returns a text rendering of the Option parameter or positional parameter; returns an empty string
3659              * {@code ""} if the option is a boolean and does not take a parameter.
3660              * @param field the annotated field with a parameter label
3661              * @param ansi determines whether ANSI escape codes should be emitted or not
3662              * @param styles the styles to apply to the parameter label
3663              * @return a text rendering of the Option parameter or positional parameter */
3664             Text renderParameterLabel(Field field, Ansi ansi, List<IStyle> styles);
3665 
3666             /** Returns the separator between option name and param label.
3667              * @return the separator between option name and param label */
3668             String separator();
3669         }
3670         /**
3671          * DefaultParamLabelRenderer separates option parameters from their {@linkplain Option options} with a
3672          * {@linkplain DefaultParamLabelRenderer#separator separator} string, surrounds optional values
3673          * with {@code '['} and {@code ']'} characters and uses ellipses ("...") to indicate that any number of
3674          * values is allowed for options or parameters with variable arity.
3675          */
3676         static class DefaultParamLabelRenderer implements IParamLabelRenderer {
3677             /** The string to use to separate option parameters from their options. */
3678             public final String separator;
3679             /** Constructs a new DefaultParamLabelRenderer with the specified separator string. */
3680             public DefaultParamLabelRenderer(final String separator) {
3681                 this.separator = Assert.notNull(separator, "separator");
3682             }
3683             @Override
3684             public String separator() { return separator; }
3685             @Override
3686             public Text renderParameterLabel(final Field field, final Ansi ansi, final List<IStyle> styles) {
3687                 final boolean isOptionParameter = field.isAnnotationPresent(Option.class);
3688                 final Range arity = isOptionParameter ? Range.optionArity(field) : Range.parameterCapacity(field);
3689                 final String split = isOptionParameter ? field.getAnnotation(Option.class).split() : field.getAnnotation(Parameters.class).split();
3690                 Text result = ansi.new Text("");
3691                 String sep = isOptionParameter ? separator : "";
3692                 Text paramName = ansi.apply(renderParameterName(field), styles);
3693                 if (!empty(split)) { paramName = paramName.append("[" + split).append(paramName).append("]..."); } // #194
3694                 for (int i = 0; i < arity.min; i++) {
3695                     result = result.append(sep).append(paramName);
3696                     sep = " ";
3697                 }
3698                 if (arity.isVariable) {
3699                     if (result.length == 0) { // arity="*" or arity="0..*"
3700                         result = result.append(sep + "[").append(paramName).append("]...");
3701                     } else if (!result.plainString().endsWith("...")) { // split param may already end with "..."
3702                         result = result.append("...");
3703                     }
3704                 } else {
3705                     sep = result.length == 0 ? (isOptionParameter ? separator : "") : " ";
3706                     for (int i = arity.min; i < arity.max; i++) {
3707                         if (sep.trim().length() == 0) {
3708                             result = result.append(sep + "[").append(paramName);
3709                         } else {
3710                             result = result.append("[" + sep).append(paramName);
3711                         }
3712                         sep  = " ";
3713                     }
3714                     for (int i = arity.min; i < arity.max; i++) { result = result.append("]"); }
3715                 }
3716                 return result;
3717             }
3718             private static String renderParameterName(final Field field) {
3719                 String result = null;
3720                 if (field.isAnnotationPresent(Option.class)) {
3721                     result = field.getAnnotation(Option.class).paramLabel();
3722                 } else if (field.isAnnotationPresent(Parameters.class)) {
3723                     result = field.getAnnotation(Parameters.class).paramLabel();
3724                 }
3725                 if (result != null && result.trim().length() > 0) {
3726                     return result.trim();
3727                 }
3728                 String name = field.getName();
3729                 if (Map.class.isAssignableFrom(field.getType())) { // #195 better param labels for map fields
3730                     final Class<?>[] paramTypes = getTypeAttribute(field);
3731                     if (paramTypes.length < 2 || paramTypes[0] == null || paramTypes[1] == null) {
3732                         name = "String=String";
3733                     } else { name = paramTypes[0].getSimpleName() + "=" + paramTypes[1].getSimpleName(); }
3734                 }
3735                 return "<" + name + ">";
3736             }
3737         }
3738         /** Use a Layout to format usage help text for options and parameters in tabular format.
3739          * <p>Delegates to the renderers to create {@link Text} values for the annotated fields, and uses a
3740          * {@link TextTable} to display these values in tabular format. Layout is responsible for deciding which values
3741          * to display where in the table. By default, Layout shows one option or parameter per table row.</p>
3742          * <p>Customize by overriding the {@link #layout(Field, CommandLine.Help.Ansi.Text[][])} method.</p>
3743          * @see IOptionRenderer rendering options to text
3744          * @see IParameterRenderer rendering parameters to text
3745          * @see TextTable showing values in a tabular format
3746          */
3747         public static class Layout {
3748             protected final ColorScheme colorScheme;
3749             protected final TextTable table;
3750             protected IOptionRenderer optionRenderer;
3751             protected IParameterRenderer parameterRenderer;
3752 
3753             /** Constructs a Layout with the specified color scheme, a new default 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             public Layout(final ColorScheme colorScheme) { this(colorScheme, new TextTable(colorScheme.ansi())); }
3758 
3759             /** Constructs a Layout with the specified color scheme, the specified TextTable, the
3760              * {@linkplain Help#createDefaultOptionRenderer() default option renderer}, and the
3761              * {@linkplain Help#createDefaultParameterRenderer() default parameter renderer}.
3762              * @param colorScheme the color scheme to use for common, auto-generated parts of the usage help message
3763              * @param textTable the TextTable to lay out parts of the usage help message in tabular format */
3764             public Layout(final ColorScheme colorScheme, final TextTable textTable) {
3765                 this(colorScheme, textTable, new DefaultOptionRenderer(), new DefaultParameterRenderer());
3766             }
3767             /** Constructs a Layout with the specified color scheme, the specified TextTable, the
3768              * specified option renderer and the specified parameter renderer.
3769              * @param colorScheme the color scheme to use for common, auto-generated parts of the usage help message
3770              * @param optionRenderer the object responsible for rendering Options to Text
3771              * @param parameterRenderer the object responsible for rendering Parameters to Text
3772              * @param textTable the TextTable to lay out parts of the usage help message in tabular format */
3773             public Layout(final ColorScheme colorScheme, final TextTable textTable, final IOptionRenderer optionRenderer, final IParameterRenderer parameterRenderer) {
3774                 this.colorScheme       = Assert.notNull(colorScheme, "colorScheme");
3775                 this.table             = Assert.notNull(textTable, "textTable");
3776                 this.optionRenderer    = Assert.notNull(optionRenderer, "optionRenderer");
3777                 this.parameterRenderer = Assert.notNull(parameterRenderer, "parameterRenderer");
3778             }
3779             /**
3780              * Copies the specified text values into the correct cells in the {@link TextTable}. This implementation
3781              * delegates to {@link TextTable#addRowValues(CommandLine.Help.Ansi.Text...)} for each row of values.
3782              * <p>Subclasses may override.</p>
3783              * @param field the field annotated with the specified Option or Parameters
3784              * @param cellValues the text values representing the Option/Parameters, to be displayed in tabular form
3785              */
3786             public void layout(final Field field, final Text[][] cellValues) {
3787                 for (final Text[] oneRow : cellValues) {
3788                     table.addRowValues(oneRow);
3789                 }
3790             }
3791             /** Calls {@link #addOption(Field, CommandLine.Help.IParamLabelRenderer)} for all non-hidden Options in the list.
3792              * @param fields fields annotated with {@link Option} to add usage descriptions for
3793              * @param paramLabelRenderer object that knows how to render option parameters */
3794             public void addOptions(final List<Field> fields, final IParamLabelRenderer paramLabelRenderer) {
3795                 for (final Field field : fields) {
3796                     final Option option = field.getAnnotation(Option.class);
3797                     if (!option.hidden()) {
3798                         addOption(field, paramLabelRenderer);
3799                     }
3800                 }
3801             }
3802             /**
3803              * Delegates to the {@link #optionRenderer option renderer} of this layout to obtain
3804              * text values for the specified {@link Option}, and then calls the {@link #layout(Field, CommandLine.Help.Ansi.Text[][])}
3805              * method to write these text values into the correct cells in the TextTable.
3806              * @param field the field annotated with the specified Option
3807              * @param paramLabelRenderer knows how to render option parameters
3808              */
3809             public void addOption(final Field field, final IParamLabelRenderer paramLabelRenderer) {
3810                 final Option option = field.getAnnotation(Option.class);
3811                 final Text[][] values = optionRenderer.render(option, field, paramLabelRenderer, colorScheme);
3812                 layout(field, values);
3813             }
3814             /** Calls {@link #addPositionalParameter(Field, CommandLine.Help.IParamLabelRenderer)} for all non-hidden Parameters in the list.
3815              * @param fields fields annotated with {@link Parameters} to add usage descriptions for
3816              * @param paramLabelRenderer knows how to render option parameters */
3817             public void addPositionalParameters(final List<Field> fields, final IParamLabelRenderer paramLabelRenderer) {
3818                 for (final Field field : fields) {
3819                     final Parameters parameters = field.getAnnotation(Parameters.class);
3820                     if (!parameters.hidden()) {
3821                         addPositionalParameter(field, paramLabelRenderer);
3822                     }
3823                 }
3824             }
3825             /**
3826              * Delegates to the {@link #parameterRenderer parameter renderer} of this layout
3827              * to obtain text values for the specified {@link Parameters}, and then calls
3828              * {@link #layout(Field, CommandLine.Help.Ansi.Text[][])} to write these text values into the correct cells in the TextTable.
3829              * @param field the field annotated with the specified Parameters
3830              * @param paramLabelRenderer knows how to render option parameters
3831              */
3832             public void addPositionalParameter(final Field field, final IParamLabelRenderer paramLabelRenderer) {
3833                 final Parameters option = field.getAnnotation(Parameters.class);
3834                 final Text[][] values = parameterRenderer.render(option, field, paramLabelRenderer, colorScheme);
3835                 layout(field, values);
3836             }
3837             /** Returns the section of the usage help message accumulated in the TextTable owned by this layout. */
3838             @Override public String toString() {
3839                 return table.toString();
3840             }
3841         }
3842         /** Sorts short strings before longer strings. */
3843         static class ShortestFirst implements Comparator<String> {
3844             @Override
3845             public int compare(final String o1, final String o2) {
3846                 return o1.length() - o2.length();
3847             }
3848             /** Sorts the specified array of Strings shortest-first and returns it. */
3849             public static String[] sort(final String[] names) {
3850                 Arrays.sort(names, new ShortestFirst());
3851                 return names;
3852             }
3853         }
3854         /** Sorts {@code Option} instances by their name in case-insensitive alphabetic order. If an Option has
3855          * multiple names, the shortest name is used for the sorting. Help options follow non-help options. */
3856         static class SortByShortestOptionNameAlphabetically implements Comparator<Field> {
3857             @Override
3858             public int compare(final Field f1, final Field f2) {
3859                 final Option o1 = f1.getAnnotation(Option.class);
3860                 final Option o2 = f2.getAnnotation(Option.class);
3861                 if (o1 == null) { return 1; } else if (o2 == null) { return -1; } // options before params
3862                 final String[] names1 = ShortestFirst.sort(o1.names());
3863                 final String[] names2 = ShortestFirst.sort(o2.names());
3864                 int result = names1[0].toUpperCase().compareTo(names2[0].toUpperCase()); // case insensitive sort
3865                 result = result == 0 ? -names1[0].compareTo(names2[0]) : result; // lower case before upper case
3866                 return o1.help() == o2.help() ? result : o2.help() ? -1 : 1; // help options come last
3867             }
3868         }
3869         /** Sorts {@code Option} instances by their max arity first, then their min arity, then delegates to super class. */
3870         static class SortByOptionArityAndNameAlphabetically extends SortByShortestOptionNameAlphabetically {
3871             @Override
3872             public int compare(final Field f1, final Field f2) {
3873                 final Option o1 = f1.getAnnotation(Option.class);
3874                 final Option o2 = f2.getAnnotation(Option.class);
3875                 final Range arity1 = Range.optionArity(f1);
3876                 final Range arity2 = Range.optionArity(f2);
3877                 int result = arity1.max - arity2.max;
3878                 if (result == 0) {
3879                     result = arity1.min - arity2.min;
3880                 }
3881                 if (result == 0) { // arity is same
3882                     if (isMultiValue(f1) && !isMultiValue(f2)) { result = 1; } // f1 > f2
3883                     if (!isMultiValue(f1) && isMultiValue(f2)) { result = -1; } // f1 < f2
3884                 }
3885                 return result == 0 ? super.compare(f1, f2) : result;
3886             }
3887         }
3888         /**
3889          * <p>Responsible for spacing out {@link Text} values according to the {@link Column} definitions the table was
3890          * created with. Columns have a width, indentation, and an overflow policy that decides what to do if a value is
3891          * longer than the column's width.</p>
3892          */
3893         public static class TextTable {
3894             /**
3895              * Helper class to index positions in a {@code Help.TextTable}.
3896              * @since 2.0
3897              */
3898             public static class Cell {
3899                 /** Table column index (zero based). */
3900                 public final int column;
3901                 /** Table row index (zero based). */
3902                 public final int row;
3903                 /** Constructs a new Cell with the specified coordinates in the table.
3904                  * @param column the zero-based table column
3905                  * @param row the zero-based table row */
3906                 public Cell(final int column, final int row) { this.column = column; this.row = row; }
3907             }
3908 
3909             /** The column definitions of this table. */
3910             public final Column[] columns;
3911 
3912             /** The {@code char[]} slots of the {@code TextTable} to copy text values into. */
3913             protected final List<Text> columnValues = new ArrayList<Text>();
3914 
3915             /** By default, indent wrapped lines by 2 spaces. */
3916             public int indentWrappedLines = 2;
3917 
3918             private final Ansi ansi;
3919 
3920             /** Constructs a TextTable with five columns as follows:
3921              * <ol>
3922              * <li>required option/parameter marker (width: 2, indent: 0, TRUNCATE on overflow)</li>
3923              * <li>short option name (width: 2, indent: 0, TRUNCATE on overflow)</li>
3924              * <li>comma separator (width: 1, indent: 0, TRUNCATE on overflow)</li>
3925              * <li>long option name(s) (width: 24, indent: 1, SPAN multiple columns on overflow)</li>
3926              * <li>description line(s) (width: 51, indent: 1, WRAP to next row on overflow)</li>
3927              * </ol>
3928              * @param ansi whether to emit ANSI escape codes or not
3929              */
3930             public TextTable(final Ansi ansi) {
3931                 // "* -c, --create                Creates a ...."
3932                 this(ansi, new Column[] {
3933                             new Column(2,                                        0, TRUNCATE), // "*"
3934                             new Column(2,                                        0, TRUNCATE), // "-c"
3935                             new Column(1,                                        0, TRUNCATE), // ","
3936                             new Column(optionsColumnWidth - 2 - 2 - 1       , 1, SPAN),  // " --create"
3937                             new Column(usageHelpWidth - optionsColumnWidth, 1, WRAP) // " Creates a ..."
3938                     });
3939             }
3940 
3941             /** Constructs a new TextTable with columns with the specified width, all SPANning  multiple columns on
3942              * overflow except the last column which WRAPS to the next row.
3943              * @param ansi whether to emit ANSI escape codes or not
3944              * @param columnWidths the width of the table columns (all columns have zero indent)
3945              */
3946             public TextTable(final Ansi ansi, final int... columnWidths) {
3947                 this.ansi = Assert.notNull(ansi, "ansi");
3948                 columns = new Column[columnWidths.length];
3949                 for (int i = 0; i < columnWidths.length; i++) {
3950                     columns[i] = new Column(columnWidths[i], 0, i == columnWidths.length - 1 ? SPAN: WRAP);
3951                 }
3952             }
3953             /** Constructs a {@code TextTable} with the specified columns.
3954              * @param ansi whether to emit ANSI escape codes or not
3955              * @param columns columns to construct this TextTable with */
3956             public TextTable(final Ansi ansi, final Column... columns) {
3957                 this.ansi = Assert.notNull(ansi, "ansi");
3958                 this.columns = Assert.notNull(columns, "columns");
3959                 if (columns.length == 0) { throw new IllegalArgumentException("At least one column is required"); }
3960             }
3961             /** Returns the {@code Text} slot at the specified row and column to write a text value into.
3962              * @param row the row of the cell whose Text to return
3963              * @param col the column of the cell whose Text to return
3964              * @return the Text object at the specified row and column
3965              * @since 2.0 */
3966             public Text textAt(final int row, final int col) { return columnValues.get(col + (row * columns.length)); }
3967 
3968             /** Returns the {@code Text} slot at the specified row and column to write a text value into.
3969              * @param row the row of the cell whose Text to return
3970              * @param col the column of the cell whose Text to return
3971              * @return the Text object at the specified row and column
3972              * @deprecated use {@link #textAt(int, int)} instead */
3973             @Deprecated
3974             public Text cellAt(final int row, final int col) { return textAt(row, col); }
3975 
3976             /** Returns the current number of rows of this {@code TextTable}.
3977              * @return the current number of rows in this TextTable */
3978             public int rowCount() { return columnValues.size() / columns.length; }
3979 
3980             /** Adds the required {@code char[]} slots for a new row to the {@link #columnValues} field. */
3981             public void addEmptyRow() {
3982                 for (int i = 0; i < columns.length; i++) {
3983                     columnValues.add(ansi.new Text(columns[i].width));
3984                 }
3985             }
3986 
3987             /** Delegates to {@link #addRowValues(CommandLine.Help.Ansi.Text...)}.
3988              * @param values the text values to display in each column of the current row */
3989             public void addRowValues(final String... values) {
3990                 final Text[] array = new Text[values.length];
3991                 for (int i = 0; i < array.length; i++) {
3992                     array[i] = values[i] == null ? Ansi.EMPTY_TEXT : ansi.new Text(values[i]);
3993                 }
3994                 addRowValues(array);
3995             }
3996             /**
3997              * Adds a new {@linkplain TextTable#addEmptyRow() empty row}, then calls {@link
3998              * TextTable#putValue(int, int, CommandLine.Help.Ansi.Text) putValue} for each of the specified values, adding more empty rows
3999              * if the return value indicates that the value spanned multiple columns or was wrapped to multiple rows.
4000              * @param values the values to write into a new row in this TextTable
4001              * @throws IllegalArgumentException if the number of values exceeds the number of Columns in this table
4002              */
4003             public void addRowValues(final Text... values) {
4004                 if (values.length > columns.length) {
4005                     throw new IllegalArgumentException(values.length + " values don't fit in " +
4006                             columns.length + " columns");
4007                 }
4008                 addEmptyRow();
4009                 for (int col = 0; col < values.length; col++) {
4010                     final int row = rowCount() - 1;// write to last row: previous value may have wrapped to next row
4011                     final Cell cell = putValue(row, col, values[col]);
4012 
4013                     // add row if a value spanned/wrapped and there are still remaining values
4014                     if ((cell.row != row || cell.column != col) && col != values.length - 1) {
4015                         addEmptyRow();
4016                     }
4017                 }
4018             }
4019             /**
4020              * Writes the specified value into the cell at the specified row and column and returns the last row and
4021              * column written to. Depending on the Column's {@link Column#overflow Overflow} policy, the value may span
4022              * multiple columns or wrap to multiple rows when larger than the column width.
4023              * @param row the target row in the table
4024              * @param col the target column in the table to write to
4025              * @param value the value to write
4026              * @return a Cell indicating the position in the table that was last written to (since 2.0)
4027              * @throws IllegalArgumentException if the specified row exceeds the table's {@linkplain
4028              *          TextTable#rowCount() row count}
4029              * @since 2.0 (previous versions returned a {@code java.awt.Point} object)
4030              */
4031             public Cell putValue(int row, int col, Text value) {
4032                 if (row > rowCount() - 1) {
4033                     throw new IllegalArgumentException("Cannot write to row " + row + ": rowCount=" + rowCount());
4034                 }
4035                 if (value == null || value.plain.length() == 0) { return new Cell(col, row); }
4036                 final Column column = columns[col];
4037                 int indent = column.indent;
4038                 switch (column.overflow) {
4039                     case TRUNCATE:
4040                         copy(value, textAt(row, col), indent);
4041                         return new Cell(col, row);
4042                     case SPAN:
4043                         final int startColumn = col;
4044                         do {
4045                             final boolean lastColumn = col == columns.length - 1;
4046                             final int charsWritten = lastColumn
4047                                     ? copy(BreakIterator.getLineInstance(), value, textAt(row, col), indent)
4048                                     : copy(value, textAt(row, col), indent);
4049                             value = value.substring(charsWritten);
4050                             indent = 0;
4051                             if (value.length > 0) { // value did not fit in column
4052                                 ++col;                // write remainder of value in next column
4053                             }
4054                             if (value.length > 0 && col >= columns.length) { // we filled up all columns on this row
4055                                 addEmptyRow();
4056                                 row++;
4057                                 col = startColumn;
4058                                 indent = column.indent + indentWrappedLines;
4059                             }
4060                         } while (value.length > 0);
4061                         return new Cell(col, row);
4062                     case WRAP:
4063                         final BreakIterator lineBreakIterator = BreakIterator.getLineInstance();
4064                         do {
4065                             final int charsWritten = copy(lineBreakIterator, value, textAt(row, col), indent);
4066                             value = value.substring(charsWritten);
4067                             indent = column.indent + indentWrappedLines;
4068                             if (value.length > 0) {  // value did not fit in column
4069                                 ++row;                 // write remainder of value in next row
4070                                 addEmptyRow();
4071                             }
4072                         } while (value.length > 0);
4073                         return new Cell(col, row);
4074                 }
4075                 throw new IllegalStateException(column.overflow.toString());
4076             }
4077             private static int length(final Text str) {
4078                 return str.length; // TODO count some characters as double length
4079             }
4080 
4081             private int copy(final BreakIterator line, final Text text, final Text columnValue, final int offset) {
4082                 // Deceive the BreakIterator to ensure no line breaks after '-' character
4083                 line.setText(text.plainString().replace("-", "\u00ff"));
4084                 int done = 0;
4085                 for (int start = line.first(), end = line.next(); end != BreakIterator.DONE; start = end, end = line.next()) {
4086                     final Text word = text.substring(start, end); //.replace("\u00ff", "-"); // not needed
4087                     if (columnValue.maxLength >= offset + done + length(word)) {
4088                         done += copy(word, columnValue, offset + done); // TODO localized length
4089                     } else {
4090                         break;
4091                     }
4092                 }
4093                 if (done == 0 && length(text) > columnValue.maxLength) {
4094                     // The value is a single word that is too big to be written to the column. Write as much as we can.
4095                     done = copy(text, columnValue, offset);
4096                 }
4097                 return done;
4098             }
4099             private static int copy(final Text value, final Text destination, final int offset) {
4100                 final int length = Math.min(value.length, destination.maxLength - offset);
4101                 value.getStyledChars(value.from, length, destination, offset);
4102                 return length;
4103             }
4104 
4105             /** Copies the text representation that we built up from the options into the specified StringBuilder.
4106              * @param text the StringBuilder to write into
4107              * @return the specified StringBuilder object (to allow method chaining and a more fluid API) */
4108             public StringBuilder toString(final StringBuilder text) {
4109                 final int columnCount = this.columns.length;
4110                 final StringBuilder row = new StringBuilder(usageHelpWidth);
4111                 for (int i = 0; i < columnValues.size(); i++) {
4112                     final Text column = columnValues.get(i);
4113                     row.append(column.toString());
4114                     row.append(new String(spaces(columns[i % columnCount].width - column.length)));
4115                     if (i % columnCount == columnCount - 1) {
4116                         int lastChar = row.length() - 1;
4117                         while (lastChar >= 0 && row.charAt(lastChar) == ' ') {lastChar--;} // rtrim
4118                         row.setLength(lastChar + 1);
4119                         text.append(row.toString()).append(System.getProperty("line.separator"));
4120                         row.setLength(0);
4121                     }
4122                 }
4123                 //if (Ansi.enabled()) { text.append(Style.reset.off()); }
4124                 return text;
4125             }
4126             @Override
4127             public String toString() { return toString(new StringBuilder()).toString(); }
4128         }
4129         /** Columns define the width, indent (leading number of spaces in a column before the value) and
4130          * {@linkplain Overflow Overflow} policy of a column in a {@linkplain TextTable TextTable}. */
4131         public static class Column {
4132 
4133             /** Policy for handling text that is longer than the column width:
4134              *  span multiple columns, wrap to the next row, or simply truncate the portion that doesn't fit. */
4135             public enum Overflow { TRUNCATE, SPAN, WRAP }
4136 
4137             /** Column width in characters */
4138             public final int width;
4139 
4140             /** Indent (number of empty spaces at the start of the column preceding the text value) */
4141             public final int indent;
4142 
4143             /** Policy that determines how to handle values larger than the column width. */
4144             public final Overflow overflow;
4145             public Column(final int width, final int indent, final Overflow overflow) {
4146                 this.width = width;
4147                 this.indent = indent;
4148                 this.overflow = Assert.notNull(overflow, "overflow");
4149             }
4150         }
4151 
4152         /** All usage help message are generated with a color scheme that assigns certain styles and colors to common
4153          * parts of a usage message: the command name, options, positional parameters and option parameters.
4154          * Users may customize these styles by creating Help with a custom color scheme.
4155          * <p>Note that these options and styles may not be rendered if ANSI escape codes are not
4156          * {@linkplain Ansi#enabled() enabled}.</p>
4157          * @see Help#defaultColorScheme(Ansi)
4158          */
4159         public static class ColorScheme {
4160             public final List<IStyle> commandStyles = new ArrayList<IStyle>();
4161             public final List<IStyle> optionStyles = new ArrayList<IStyle>();
4162             public final List<IStyle> parameterStyles = new ArrayList<IStyle>();
4163             public final List<IStyle> optionParamStyles = new ArrayList<IStyle>();
4164             private final Ansi ansi;
4165 
4166             /** Constructs a new ColorScheme with {@link Help.Ansi#AUTO}. */
4167             public ColorScheme() { this(Ansi.AUTO); }
4168 
4169             /** Constructs a new ColorScheme with the specified Ansi enabled mode.
4170              * @param ansi whether to emit ANSI escape codes or not
4171              */
4172             public ColorScheme(final Ansi ansi) {this.ansi = Assert.notNull(ansi, "ansi"); }
4173 
4174             /** Adds the specified styles to the registered styles for commands in this color scheme and returns this color scheme.
4175              * @param styles the styles to add to the registered styles for commands in this color scheme
4176              * @return this color scheme to enable method chaining for a more fluent API */
4177             public ColorScheme commands(final IStyle... styles)     { return addAll(commandStyles, styles); }
4178             /** Adds the specified styles to the registered styles for options in this color scheme and returns this color scheme.
4179              * @param styles the styles to add to registered the styles for options in this color scheme
4180              * @return this color scheme to enable method chaining for a more fluent API */
4181             public ColorScheme options(final IStyle... styles)      { return addAll(optionStyles, styles);}
4182             /** Adds the specified styles to the registered styles for positional parameters in this color scheme and returns this color scheme.
4183              * @param styles the styles to add to registered the styles for parameters in this color scheme
4184              * @return this color scheme to enable method chaining for a more fluent API */
4185             public ColorScheme parameters(final IStyle... styles)   { return addAll(parameterStyles, styles);}
4186             /** Adds the specified styles to the registered styles for option parameters in this color scheme and returns this color scheme.
4187              * @param styles the styles to add to the registered styles for option parameters in this color scheme
4188              * @return this color scheme to enable method chaining for a more fluent API */
4189             public ColorScheme optionParams(final IStyle... styles) { return addAll(optionParamStyles, styles);}
4190             /** Returns a Text with all command styles applied to the specified command string.
4191              * @param command the command string to apply the registered command styles to
4192              * @return a Text with all command styles applied to the specified command string */
4193             public Ansi.Text commandText(final String command)         { return ansi().apply(command,     commandStyles); }
4194             /** Returns a Text with all option styles applied to the specified option string.
4195              * @param option the option string to apply the registered option styles to
4196              * @return a Text with all option styles applied to the specified option string */
4197             public Ansi.Text optionText(final String option)           { return ansi().apply(option,      optionStyles); }
4198             /** Returns a Text with all parameter styles applied to the specified parameter string.
4199              * @param parameter the parameter string to apply the registered parameter styles to
4200              * @return a Text with all parameter styles applied to the specified parameter string */
4201             public Ansi.Text parameterText(final String parameter)     { return ansi().apply(parameter,   parameterStyles); }
4202             /** Returns a Text with all optionParam styles applied to the specified optionParam string.
4203              * @param optionParam the option parameter string to apply the registered option parameter styles to
4204              * @return a Text with all option parameter styles applied to the specified option parameter string */
4205             public Ansi.Text optionParamText(final String optionParam) { return ansi().apply(optionParam, optionParamStyles); }
4206 
4207             /** Replaces colors and styles in this scheme with ones specified in system properties, and returns this scheme.
4208              * Supported property names:<ul>
4209              *     <li>{@code picocli.color.commands}</li>
4210              *     <li>{@code picocli.color.options}</li>
4211              *     <li>{@code picocli.color.parameters}</li>
4212              *     <li>{@code picocli.color.optionParams}</li>
4213              * </ul><p>Property values can be anything that {@link Help.Ansi.Style#parse(String)} can handle.</p>
4214              * @return this ColorScheme
4215              */
4216             public ColorScheme applySystemProperties() {
4217                 replace(commandStyles,     System.getProperty("picocli.color.commands"));
4218                 replace(optionStyles,      System.getProperty("picocli.color.options"));
4219                 replace(parameterStyles,   System.getProperty("picocli.color.parameters"));
4220                 replace(optionParamStyles, System.getProperty("picocli.color.optionParams"));
4221                 return this;
4222             }
4223             private void replace(final List<IStyle> styles, final String property) {
4224                 if (property != null) {
4225                     styles.clear();
4226                     addAll(styles, Style.parse(property));
4227                 }
4228             }
4229             private ColorScheme addAll(final List<IStyle> styles, final IStyle... add) {
4230                 styles.addAll(Arrays.asList(add));
4231                 return this;
4232             }
4233 
4234             public Ansi ansi() {
4235                 return ansi;
4236             }
4237         }
4238 
4239         /** Creates and returns a new {@link ColorScheme} initialized with picocli default values: commands are bold,
4240          *  options and parameters use a yellow foreground, and option parameters use italic.
4241          * @param ansi whether the usage help message should contain ANSI escape codes or not
4242          * @return a new default color scheme
4243          */
4244         public static ColorScheme defaultColorScheme(final Ansi ansi) {
4245             return new ColorScheme(ansi)
4246                     .commands(Style.bold)
4247                     .options(Style.fg_yellow)
4248                     .parameters(Style.fg_yellow)
4249                     .optionParams(Style.italic);
4250         }
4251 
4252         /** Provides methods and inner classes to support using ANSI escape codes in usage help messages. */
4253         public enum Ansi {
4254             /** Only emit ANSI escape codes if the platform supports it and system property {@code "picocli.ansi"}
4255              * is not set to any value other than {@code "true"} (case insensitive). */
4256             AUTO,
4257             /** Forced ON: always emit ANSI escape code regardless of the platform. */
4258             ON,
4259             /** Forced OFF: never emit ANSI escape code regardless of the platform. */
4260             OFF;
4261             static Text EMPTY_TEXT = OFF.new Text(0);
4262             static final boolean isWindows  = System.getProperty("os.name").startsWith("Windows");
4263             static final boolean isXterm    = System.getenv("TERM") != null && System.getenv("TERM").startsWith("xterm");
4264             static final boolean ISATTY = calcTTY();
4265 
4266             // http://stackoverflow.com/questions/1403772/how-can-i-check-if-a-java-programs-input-output-streams-are-connected-to-a-term
4267             static final boolean calcTTY() {
4268                 if (isWindows && isXterm) { return true; } // Cygwin uses pseudo-tty and console is always null...
4269                 try { return System.class.getDeclaredMethod("console").invoke(null) != null; }
4270                 catch (final Throwable reflectionFailed) { return true; }
4271             }
4272             private static boolean ansiPossible() { return ISATTY && (!isWindows || isXterm); }
4273 
4274             /** Returns {@code true} if ANSI escape codes should be emitted, {@code false} otherwise.
4275              * @return ON: {@code true}, OFF: {@code false}, AUTO: if system property {@code "picocli.ansi"} is
4276              *      defined then return its boolean value, otherwise return whether the platform supports ANSI escape codes */
4277             public boolean enabled() {
4278                 if (this == ON)  { return true; }
4279                 if (this == OFF) { return false; }
4280                 return (System.getProperty("picocli.ansi") == null ? ansiPossible() : Boolean.getBoolean("picocli.ansi"));
4281             }
4282 
4283             /** Defines the interface for an ANSI escape sequence. */
4284             public interface IStyle {
4285 
4286                 /** The Control Sequence Introducer (CSI) escape sequence {@value}. */
4287                 String CSI = "\u001B[";
4288 
4289                 /** Returns the ANSI escape code for turning this style on.
4290                  * @return the ANSI escape code for turning this style on */
4291                 String on();
4292 
4293                 /** Returns the ANSI escape code for turning this style off.
4294                  * @return the ANSI escape code for turning this style off */
4295                 String off();
4296             }
4297 
4298             /**
4299              * A set of pre-defined ANSI escape code styles and colors, and a set of convenience methods for parsing
4300              * text with embedded markup style names, as well as convenience methods for converting
4301              * styles to strings with embedded escape codes.
4302              */
4303             public enum Style implements IStyle {
4304                 reset(0, 0), bold(1, 21), faint(2, 22), italic(3, 23), underline(4, 24), blink(5, 25), reverse(7, 27),
4305                 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),
4306                 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),
4307                 ;
4308                 private final int startCode;
4309                 private final int endCode;
4310 
4311                 Style(final int startCode, final int endCode) {this.startCode = startCode; this.endCode = endCode; }
4312                 @Override
4313                 public String on() { return CSI + startCode + "m"; }
4314                 @Override
4315                 public String off() { return CSI + endCode + "m"; }
4316 
4317 				/** Returns the concatenated ANSI escape codes for turning all specified styles on.
4318                  * @param styles the styles to generate ANSI escape codes for
4319                  * @return the concatenated ANSI escape codes for turning all specified styles on */
4320                 public static String on(final IStyle... styles) {
4321                     final StringBuilder result = new StringBuilder();
4322                     for (final IStyle style : styles) {
4323                         result.append(style.on());
4324                     }
4325                     return result.toString();
4326                 }
4327 				/** Returns the concatenated ANSI escape codes for turning all specified styles off.
4328                  * @param styles the styles to generate ANSI escape codes for
4329                  * @return the concatenated ANSI escape codes for turning all specified styles off */
4330                 public static String off(final IStyle... styles) {
4331                     final StringBuilder result = new StringBuilder();
4332                     for (final IStyle style : styles) {
4333                         result.append(style.off());
4334                     }
4335                     return result.toString();
4336                 }
4337 				/** Parses the specified style markup and returns the associated style.
4338 				 *  The markup may be one of the Style enum value names, or it may be one of the Style enum value
4339 				 *  names when {@code "fg_"} is prepended, or it may be one of the indexed colors in the 256 color palette.
4340                  * @param str the case-insensitive style markup to convert, e.g. {@code "blue"} or {@code "fg_blue"},
4341                  *          or {@code "46"} (indexed color) or {@code "0;5;0"} (RGB components of an indexed color)
4342 				 * @return the IStyle for the specified converter
4343 				 */
4344                 public static IStyle fg(final String str) {
4345                     try { return Style.valueOf(str.toLowerCase(ENGLISH)); } catch (final Exception ignored) {}
4346                     try { return Style.valueOf("fg_" + str.toLowerCase(ENGLISH)); } catch (final Exception ignored) {}
4347                     return new Palette256Color(true, str);
4348                 }
4349 				/** Parses the specified style markup and returns the associated style.
4350 				 *  The markup may be one of the Style enum value names, or it may be one of the Style enum value
4351 				 *  names when {@code "bg_"} is prepended, or it may be one of the indexed colors in the 256 color palette.
4352 				 * @param str the case-insensitive style markup to convert, e.g. {@code "blue"} or {@code "bg_blue"},
4353                  *          or {@code "46"} (indexed color) or {@code "0;5;0"} (RGB components of an indexed color)
4354 				 * @return the IStyle for the specified converter
4355 				 */
4356                 public static IStyle bg(final String str) {
4357                     try { return Style.valueOf(str.toLowerCase(ENGLISH)); } catch (final Exception ignored) {}
4358                     try { return Style.valueOf("bg_" + str.toLowerCase(ENGLISH)); } catch (final Exception ignored) {}
4359                     return new Palette256Color(false, str);
4360                 }
4361                 /** Parses the specified comma-separated sequence of style descriptors and returns the associated
4362                  *  styles. For each markup, strings starting with {@code "bg("} are delegated to
4363                  *  {@link #bg(String)}, others are delegated to {@link #bg(String)}.
4364                  * @param commaSeparatedCodes one or more descriptors, e.g. {@code "bg(blue),underline,red"}
4365                  * @return an array with all styles for the specified descriptors
4366                  */
4367                 public static IStyle[] parse(final String commaSeparatedCodes) {
4368                     final String[] codes = commaSeparatedCodes.split(",");
4369                     final IStyle[] styles = new IStyle[codes.length];
4370                     for(int i = 0; i < codes.length; ++i) {
4371                         if (codes[i].toLowerCase(ENGLISH).startsWith("fg(")) {
4372                             final int end = codes[i].indexOf(')');
4373                             styles[i] = Style.fg(codes[i].substring(3, end < 0 ? codes[i].length() : end));
4374                         } else if (codes[i].toLowerCase(ENGLISH).startsWith("bg(")) {
4375                             final int end = codes[i].indexOf(')');
4376                             styles[i] = Style.bg(codes[i].substring(3, end < 0 ? codes[i].length() : end));
4377                         } else {
4378                             styles[i] = Style.fg(codes[i]);
4379                         }
4380                     }
4381                     return styles;
4382                 }
4383             }
4384 
4385             /** Defines a palette map of 216 colors: 6 * 6 * 6 cube (216 colors):
4386              * 16 + 36 * r + 6 * g + b (0 &lt;= r, g, b &lt;= 5). */
4387             static class Palette256Color implements IStyle {
4388                 private final int fgbg;
4389                 private final int color;
4390 
4391                 Palette256Color(final boolean foreground, final String color) {
4392                     this.fgbg = foreground ? 38 : 48;
4393                     final String[] rgb = color.split(";");
4394                     if (rgb.length == 3) {
4395                         this.color = 16 + 36 * Integer.decode(rgb[0]) + 6 * Integer.decode(rgb[1]) + Integer.decode(rgb[2]);
4396                     } else {
4397                         this.color = Integer.decode(color);
4398                     }
4399                 }
4400                 @Override
4401                 public String on() { return String.format(CSI + "%d;5;%dm", fgbg, color); }
4402                 @Override
4403                 public String off() { return CSI + (fgbg + 1) + "m"; }
4404             }
4405             private static class StyledSection {
4406                 int startIndex, length;
4407                 String startStyles, endStyles;
4408                 StyledSection(final int start, final int len, final String style1, final String style2) {
4409                     startIndex = start; length = len; startStyles = style1; endStyles = style2;
4410                 }
4411                 StyledSection withStartIndex(final int newStart) {
4412                     return new StyledSection(newStart, length, startStyles, endStyles);
4413                 }
4414             }
4415 
4416             /**
4417              * Returns a new Text object where all the specified styles are applied to the full length of the
4418              * specified plain text.
4419              * @param plainText the string to apply all styles to. Must not contain markup!
4420              * @param styles the styles to apply to the full plain text
4421              * @return a new Text object
4422              */
4423             public Text apply(final String plainText, final List<IStyle> styles) {
4424                 if (plainText.length() == 0) { return new Text(0); }
4425                 final Text result = new Text(plainText.length());
4426                 final IStyle[] all = styles.toArray(new IStyle[styles.size()]);
4427                 result.sections.add(new StyledSection(
4428                         0, plainText.length(), Style.on(all), Style.off(reverse(all)) + Style.reset.off()));
4429                 result.plain.append(plainText);
4430                 result.length = result.plain.length();
4431                 return result;
4432             }
4433 
4434             private static <T> T[] reverse(final T[] all) {
4435                 for (int i = 0; i < all.length / 2; i++) {
4436                     final T temp = all[i];
4437                     all[i] = all[all.length - i - 1];
4438                     all[all.length - i - 1] = temp;
4439                 }
4440                 return all;
4441             }
4442             /** Encapsulates rich text with styles and colors. Text objects may be constructed with Strings containing
4443              * markup like {@code @|bg(red),white,underline some text|@}, and this class converts the markup to ANSI
4444              * escape codes.
4445              * <p>
4446              * Internally keeps both an enriched and a plain text representation to allow layout components to calculate
4447              * text width while remaining unaware of the embedded ANSI escape codes.</p> */
4448             public class Text implements Cloneable {
4449                 private final int maxLength;
4450                 private int from;
4451                 private int length;
4452                 private StringBuilder plain = new StringBuilder();
4453                 private List<StyledSection> sections = new ArrayList<StyledSection>();
4454 
4455                 /** Constructs a Text with the specified max length (for use in a TextTable Column).
4456                  * @param maxLength max length of this text */
4457                 public Text(final int maxLength) { this.maxLength = maxLength; }
4458 
4459                 /**
4460                  * Constructs a Text with the specified String, which may contain markup like
4461                  * {@code @|bg(red),white,underline some text|@}.
4462                  * @param input the string with markup to parse
4463                  */
4464                 public Text(final String input) {
4465                     maxLength = -1;
4466                     plain.setLength(0);
4467                     int i = 0;
4468 
4469                     while (true) {
4470                         int j = input.indexOf("@|", i);
4471                         if (j == -1) {
4472                             if (i == 0) {
4473                                 plain.append(input);
4474                                 length = plain.length();
4475                                 return;
4476                             }
4477                             plain.append(input.substring(i, input.length()));
4478                             length = plain.length();
4479                             return;
4480                         }
4481                         plain.append(input.substring(i, j));
4482                         final int k = input.indexOf("|@", j);
4483                         if (k == -1) {
4484                             plain.append(input);
4485                             length = plain.length();
4486                             return;
4487                         }
4488 
4489                         j += 2;
4490                         final String spec = input.substring(j, k);
4491                         final String[] items = spec.split(" ", 2);
4492                         if (items.length == 1) {
4493                             plain.append(input);
4494                             length = plain.length();
4495                             return;
4496                         }
4497 
4498                         final IStyle[] styles = Style.parse(items[0]);
4499                         addStyledSection(plain.length(), items[1].length(),
4500                                 Style.on(styles), Style.off(reverse(styles)) + Style.reset.off());
4501                         plain.append(items[1]);
4502                         i = k + 2;
4503                     }
4504                 }
4505                 private void addStyledSection(final int start, final int length, final String startStyle, final String endStyle) {
4506                     sections.add(new StyledSection(start, length, startStyle, endStyle));
4507                 }
4508                 @Override
4509                 public Object clone() {
4510                     try { return super.clone(); } catch (final CloneNotSupportedException e) { throw new IllegalStateException(e); }
4511                 }
4512 
4513                 public Text[] splitLines() {
4514                     final List<Text> result = new ArrayList<Text>();
4515                     boolean trailingEmptyString = false;
4516                     int start = 0, end = 0;
4517                     for (int i = 0; i < plain.length(); i++, end = i) {
4518                         final char c = plain.charAt(i);
4519                         boolean eol = c == '\n';
4520                         eol |= (c == '\r' && i + 1 < plain.length() && plain.charAt(i + 1) == '\n' && ++i > 0); // \r\n
4521                         eol |= c == '\r';
4522                         if (eol) {
4523                             result.add(this.substring(start, end));
4524                             trailingEmptyString = i == plain.length() - 1;
4525                             start = i + 1;
4526                         }
4527                     }
4528                     if (start < plain.length() || trailingEmptyString) {
4529                         result.add(this.substring(start, plain.length()));
4530                     }
4531                     return result.toArray(new Text[result.size()]);
4532                 }
4533 
4534                 /** Returns a new {@code Text} instance that is a substring of this Text. Does not modify this instance!
4535                  * @param start index in the plain text where to start the substring
4536                  * @return a new Text instance that is a substring of this Text */
4537                 public Text substring(final int start) {
4538                     return substring(start, length);
4539                 }
4540 
4541                 /** Returns a new {@code Text} instance that is a substring of this Text. Does not modify this instance!
4542                  * @param start index in the plain text where to start the substring
4543                  * @param end index in the plain text where to end the substring
4544                  * @return a new Text instance that is a substring of this Text */
4545                 public Text substring(final int start, final int end) {
4546                     final Text result = (Text) clone();
4547                     result.from = from + start;
4548                     result.length = end - start;
4549                     return result;
4550                 }
4551                 /** Returns a new {@code Text} instance with the specified text appended. Does not modify this instance!
4552                  * @param string the text to append
4553                  * @return a new Text instance */
4554                 public Text append(final String string) {
4555                     return append(new Text(string));
4556                 }
4557 
4558                 /** Returns a new {@code Text} instance with the specified text appended. Does not modify this instance!
4559                  * @param other the text to append
4560                  * @return a new Text instance */
4561                 public Text append(final Text other) {
4562                     final Text result = (Text) clone();
4563                     result.plain = new StringBuilder(plain.toString().substring(from, from + length));
4564                     result.from = 0;
4565                     result.sections = new ArrayList<StyledSection>();
4566                     for (final StyledSection section : sections) {
4567                         result.sections.add(section.withStartIndex(section.startIndex - from));
4568                     }
4569                     result.plain.append(other.plain.toString().substring(other.from, other.from + other.length));
4570                     for (final StyledSection section : other.sections) {
4571                         final int index = result.length + section.startIndex - other.from;
4572                         result.sections.add(section.withStartIndex(index));
4573                     }
4574                     result.length = result.plain.length();
4575                     return result;
4576                 }
4577 
4578                 /**
4579                  * Copies the specified substring of this Text into the specified destination, preserving the markup.
4580                  * @param from start of the substring
4581                  * @param length length of the substring
4582                  * @param destination destination Text to modify
4583                  * @param offset indentation (padding)
4584                  */
4585                 public void getStyledChars(final int from, final int length, final Text destination, final int offset) {
4586                     if (destination.length < offset) {
4587                         for (int i = destination.length; i < offset; i++) {
4588                             destination.plain.append(' ');
4589                         }
4590                         destination.length = offset;
4591                     }
4592                     for (final StyledSection section : sections) {
4593                         destination.sections.add(section.withStartIndex(section.startIndex - from + destination.length));
4594                     }
4595                     destination.plain.append(plain.toString().substring(from, from + length));
4596                     destination.length = destination.plain.length();
4597                 }
4598                 /** Returns the plain text without any formatting.
4599                  * @return the plain text without any formatting */
4600                 public String plainString() {  return plain.toString().substring(from, from + length); }
4601 
4602                 @Override
4603                 public boolean equals(final Object obj) { return toString().equals(String.valueOf(obj)); }
4604                 @Override
4605                 public int hashCode() { return toString().hashCode(); }
4606 
4607                 /** Returns a String representation of the text with ANSI escape codes embedded, unless ANSI is
4608                  * {@linkplain Ansi#enabled()} not enabled}, in which case the plain text is returned.
4609                  * @return a String representation of the text with ANSI escape codes embedded (if enabled) */
4610                 @Override
4611                 public String toString() {
4612                     if (!Ansi.this.enabled()) {
4613                         return plain.toString().substring(from, from + length);
4614                     }
4615                     if (length == 0) { return ""; }
4616                     final StringBuilder sb = new StringBuilder(plain.length() + 20 * sections.size());
4617                     StyledSection current = null;
4618                     final int end = Math.min(from + length, plain.length());
4619                     for (int i = from; i < end; i++) {
4620                         final StyledSection section = findSectionContaining(i);
4621                         if (section != current) {
4622                             if (current != null) { sb.append(current.endStyles); }
4623                             if (section != null) { sb.append(section.startStyles); }
4624                             current = section;
4625                         }
4626                         sb.append(plain.charAt(i));
4627                     }
4628                     if (current != null) { sb.append(current.endStyles); }
4629                     return sb.toString();
4630                 }
4631 
4632                 private StyledSection findSectionContaining(final int index) {
4633                     for (final StyledSection section : sections) {
4634                         if (index >= section.startIndex && index < section.startIndex + section.length) {
4635                             return section;
4636                         }
4637                     }
4638                     return null;
4639                 }
4640             }
4641         }
4642     }
4643 
4644     /**
4645      * Utility class providing some defensive coding convenience methods.
4646      */
4647     private static final class Assert {
4648         /**
4649          * Throws a NullPointerException if the specified object is null.
4650          * @param object the object to verify
4651          * @param description error message
4652          * @param <T> type of the object to check
4653          * @return the verified object
4654          */
4655         static <T> T notNull(final T object, final String description) {
4656             if (object == null) {
4657                 throw new NullPointerException(description);
4658             }
4659             return object;
4660         }
4661         private Assert() {} // private constructor: never instantiate
4662     }
4663     private enum TraceLevel { OFF, WARN, INFO, DEBUG;
4664         public boolean isEnabled(final TraceLevel other) { return ordinal() >= other.ordinal(); }
4665         private void print(final Tracer tracer, final String msg, final Object... params) {
4666             if (tracer.level.isEnabled(this)) { tracer.stream.printf(prefix(msg), params); }
4667         }
4668         private String prefix(final String msg) { return "[picocli " + this + "] " + msg; }
4669         static TraceLevel lookup(final String key) { return key == null ? WARN : empty(key) || "true".equalsIgnoreCase(key) ? INFO : valueOf(key); }
4670     }
4671     private static class Tracer {
4672         TraceLevel level = TraceLevel.lookup(System.getProperty("picocli.trace"));
4673         PrintStream stream = System.err;
4674         void warn (final String msg, final Object... params) { TraceLevel.WARN.print(this, msg, params); }
4675         void info (final String msg, final Object... params) { TraceLevel.INFO.print(this, msg, params); }
4676         void debug(final String msg, final Object... params) { TraceLevel.DEBUG.print(this, msg, params); }
4677         boolean isWarn()  { return level.isEnabled(TraceLevel.WARN); }
4678         boolean isInfo()  { return level.isEnabled(TraceLevel.INFO); }
4679         boolean isDebug() { return level.isEnabled(TraceLevel.DEBUG); }
4680     }
4681     /** Base class of all exceptions thrown by {@code picocli.CommandLine}.
4682      * @since 2.0 */
4683     public static class PicocliException extends RuntimeException {
4684         private static final long serialVersionUID = -2574128880125050818L;
4685         public PicocliException(final String msg) { super(msg); }
4686         public PicocliException(final String msg, final Exception ex) { super(msg, ex); }
4687     }
4688     /** Exception indicating a problem during {@code CommandLine} initialization.
4689      * @since 2.0 */
4690     public static class InitializationException extends PicocliException {
4691         private static final long serialVersionUID = 8423014001666638895L;
4692         public InitializationException(final String msg) { super(msg); }
4693         public InitializationException(final String msg, final Exception ex) { super(msg, ex); }
4694     }
4695     /** Exception indicating a problem while invoking a command or subcommand.
4696      * @since 2.0 */
4697     public static class ExecutionException extends PicocliException {
4698         private static final long serialVersionUID = 7764539594267007998L;
4699         private final CommandLine commandLine;
4700         public ExecutionException(final CommandLine commandLine, final String msg) {
4701             super(msg);
4702             this.commandLine = Assert.notNull(commandLine, "commandLine");
4703         }
4704         public ExecutionException(final CommandLine commandLine, final String msg, final Exception ex) {
4705             super(msg, ex);
4706             this.commandLine = Assert.notNull(commandLine, "commandLine");
4707         }
4708         /** Returns the {@code CommandLine} object for the (sub)command that could not be invoked.
4709          * @return the {@code CommandLine} object for the (sub)command where invocation failed.
4710          */
4711         public CommandLine getCommandLine() { return commandLine; }
4712     }
4713 
4714     /** Exception thrown by {@link ITypeConverter} implementations to indicate a String could not be converted. */
4715     public static class TypeConversionException extends PicocliException {
4716         private static final long serialVersionUID = 4251973913816346114L;
4717         public TypeConversionException(final String msg) { super(msg); }
4718     }
4719     /** Exception indicating something went wrong while parsing command line options. */
4720     public static class ParameterException extends PicocliException {
4721         private static final long serialVersionUID = 1477112829129763139L;
4722         private final CommandLine commandLine;
4723 
4724         /** Constructs a new ParameterException with the specified CommandLine and error message.
4725          * @param commandLine the command or subcommand whose input was invalid
4726          * @param msg describes the problem
4727          * @since 2.0 */
4728         public ParameterException(final CommandLine commandLine, final String msg) {
4729             super(msg);
4730             this.commandLine = Assert.notNull(commandLine, "commandLine");
4731         }
4732         /** Constructs a new ParameterException with the specified CommandLine and error message.
4733          * @param commandLine the command or subcommand whose input was invalid
4734          * @param msg describes the problem
4735          * @param ex the exception that caused this ParameterException
4736          * @since 2.0 */
4737         public ParameterException(final CommandLine commandLine, final String msg, final Exception ex) {
4738             super(msg, ex);
4739             this.commandLine = Assert.notNull(commandLine, "commandLine");
4740         }
4741 
4742         /** Returns the {@code CommandLine} object for the (sub)command whose input could not be parsed.
4743          * @return the {@code CommandLine} object for the (sub)command where parsing failed.
4744          * @since 2.0
4745          */
4746         public CommandLine getCommandLine() { return commandLine; }
4747 
4748         private static ParameterException create(final CommandLine cmd, final Exception ex, final String arg, final int i, final String[] args) {
4749             final String msg = ex.getClass().getSimpleName() + ": " + ex.getLocalizedMessage()
4750                     + " while processing argument at or before arg[" + i + "] '" + arg + "' in " + Arrays.toString(args) + ": " + ex.toString();
4751             return new ParameterException(cmd, msg, ex);
4752         }
4753     }
4754     /**
4755      * Exception indicating that a required parameter was not specified.
4756      */
4757     public static class MissingParameterException extends ParameterException {
4758         private static final long serialVersionUID = 5075678535706338753L;
4759         public MissingParameterException(final CommandLine commandLine, final String msg) {
4760             super(commandLine, msg);
4761         }
4762 
4763         private static MissingParameterException create(final CommandLine cmd, final Collection<Field> missing, final String separator) {
4764             if (missing.size() == 1) {
4765                 return new MissingParameterException(cmd, "Missing required option '"
4766                         + describe(missing.iterator().next(), separator) + "'");
4767             }
4768             final List<String> names = new ArrayList<String>(missing.size());
4769             for (final Field field : missing) {
4770                 names.add(describe(field, separator));
4771             }
4772             return new MissingParameterException(cmd, "Missing required options " + names.toString());
4773         }
4774         private static String describe(final Field field, final String separator) {
4775             final String prefix = (field.isAnnotationPresent(Option.class))
4776                 ? field.getAnnotation(Option.class).names()[0] + separator
4777                 : "params[" + field.getAnnotation(Parameters.class).index() + "]" + separator;
4778             return prefix + Help.DefaultParamLabelRenderer.renderParameterName(field);
4779         }
4780     }
4781 
4782     /**
4783      * Exception indicating that multiple fields have been annotated with the same Option name.
4784      */
4785     public static class DuplicateOptionAnnotationsException extends InitializationException {
4786         private static final long serialVersionUID = -3355128012575075641L;
4787         public DuplicateOptionAnnotationsException(final String msg) { super(msg); }
4788 
4789         private static DuplicateOptionAnnotationsException create(final String name, final Field field1, final Field field2) {
4790             return new DuplicateOptionAnnotationsException("Option name '" + name + "' is used by both " +
4791                     field1.getDeclaringClass().getName() + "." + field1.getName() + " and " +
4792                     field2.getDeclaringClass().getName() + "." + field2.getName());
4793         }
4794     }
4795     /** Exception indicating that there was a gap in the indices of the fields annotated with {@link Parameters}. */
4796     public static class ParameterIndexGapException extends InitializationException {
4797         private static final long serialVersionUID = -1520981133257618319L;
4798         public ParameterIndexGapException(final String msg) { super(msg); }
4799     }
4800     /** Exception indicating that a command line argument could not be mapped to any of the fields annotated with
4801      * {@link Option} or {@link Parameters}. */
4802     public static class UnmatchedArgumentException extends ParameterException {
4803         private static final long serialVersionUID = -8700426380701452440L;
4804         public UnmatchedArgumentException(final CommandLine commandLine, final String msg) { super(commandLine, msg); }
4805         public UnmatchedArgumentException(final CommandLine commandLine, final Stack<String> args) { this(commandLine, new ArrayList<String>(reverse(args))); }
4806         public UnmatchedArgumentException(final CommandLine commandLine, final List<String> args) { this(commandLine, "Unmatched argument" + (args.size() == 1 ? " " : "s ") + args); }
4807     }
4808     /** Exception indicating that more values were specified for an option or parameter than its {@link Option#arity() arity} allows. */
4809     public static class MaxValuesforFieldExceededException extends ParameterException {
4810         private static final long serialVersionUID = 6536145439570100641L;
4811         public MaxValuesforFieldExceededException(final CommandLine commandLine, final String msg) { super(commandLine, msg); }
4812     }
4813     /** Exception indicating that an option for a single-value option field has been specified multiple times on the command line. */
4814     public static class OverwrittenOptionException extends ParameterException {
4815         private static final long serialVersionUID = 1338029208271055776L;
4816         public OverwrittenOptionException(final CommandLine commandLine, final String msg) { super(commandLine, msg); }
4817     }
4818     /**
4819      * Exception indicating that an annotated field had a type for which no {@link ITypeConverter} was
4820      * {@linkplain #registerConverter(Class, ITypeConverter) registered}.
4821      */
4822     public static class MissingTypeConverterException extends ParameterException {
4823         private static final long serialVersionUID = -6050931703233083760L;
4824         public MissingTypeConverterException(final CommandLine commandLine, final String msg) { super(commandLine, msg); }
4825     }
4826 }