aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/java/jopt-simple/src/main/java/joptsimple/BuiltinHelpFormatter.java
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/java/jopt-simple/src/main/java/joptsimple/BuiltinHelpFormatter.java')
-rw-r--r--third_party/java/jopt-simple/src/main/java/joptsimple/BuiltinHelpFormatter.java565
1 files changed, 565 insertions, 0 deletions
diff --git a/third_party/java/jopt-simple/src/main/java/joptsimple/BuiltinHelpFormatter.java b/third_party/java/jopt-simple/src/main/java/joptsimple/BuiltinHelpFormatter.java
new file mode 100644
index 0000000000..51ec603e6f
--- /dev/null
+++ b/third_party/java/jopt-simple/src/main/java/joptsimple/BuiltinHelpFormatter.java
@@ -0,0 +1,565 @@
+/*
+ The MIT License
+
+ Copyright (c) 2004-2015 Paul R. Holser, Jr.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package joptsimple;
+
+import java.util.*;
+
+import joptsimple.internal.Messages;
+import joptsimple.internal.Rows;
+import joptsimple.internal.Strings;
+
+import static joptsimple.ParserRules.*;
+import static joptsimple.internal.Classes.*;
+import static joptsimple.internal.Strings.*;
+
+/**
+ * <p>A help formatter that allows configuration of overall row width and column separator width.</p>
+ *
+ * <p>The formatter produces output in two sections: one for the options, and one for non-option arguments.</p>
+ *
+ * <p>The options section has two columns: the left column for the options, and the right column for their
+ * descriptions. The formatter will allow as much space as possible for the descriptions, by minimizing the option
+ * column's width, no greater than slightly less than half the overall desired width.</p>
+ *
+ * <p>The non-option arguments section is one column, occupying as much width as it can.</p>
+ *
+ * <p>Subclasses are free to override bits of this implementation as they see fit. Inspect the code
+ * carefully to understand the flow of control that this implementation guarantees.</p>
+ *
+ * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
+ */
+public class BuiltinHelpFormatter implements HelpFormatter {
+ private final Rows nonOptionRows;
+ private final Rows optionRows;
+
+ /**
+ * Makes a formatter with a pre-configured overall row width and column separator width.
+ */
+ BuiltinHelpFormatter() {
+ this( 80, 2 );
+ }
+
+ /**
+ * Makes a formatter with a given overall row width and column separator width.
+ *
+ * @param desiredOverallWidth how many characters wide to make the overall help display
+ * @param desiredColumnSeparatorWidth how many characters wide to make the separation between option column and
+ * description column
+ */
+ public BuiltinHelpFormatter( int desiredOverallWidth, int desiredColumnSeparatorWidth ) {
+ nonOptionRows = new Rows( desiredOverallWidth * 2, 0 );
+ optionRows = new Rows( desiredOverallWidth, desiredColumnSeparatorWidth );
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation:</p>
+ * <ul>
+ * <li>Sorts the given descriptors by their first elements of {@link OptionDescriptor#options()}</li>
+ * <li>Passes the resulting sorted set to {@link #addRows(java.util.Collection)}</li>
+ * <li>Returns the result of {@link #formattedHelpOutput()}</li>
+ * </ul>
+ */
+ public String format( Map<String, ? extends OptionDescriptor> options ) {
+ optionRows.reset();
+ nonOptionRows.reset();
+
+ Comparator<OptionDescriptor> comparator =
+ new Comparator<OptionDescriptor>() {
+ public int compare( OptionDescriptor first, OptionDescriptor second ) {
+ return first.options().iterator().next().compareTo( second.options().iterator().next() );
+ }
+ };
+
+ Set<OptionDescriptor> sorted = new TreeSet<>( comparator );
+ sorted.addAll( options.values() );
+
+ addRows( sorted );
+
+ return formattedHelpOutput();
+ }
+
+ /**
+ * Adds a row of option help output in the left column, with empty space in the right column.
+ *
+ * @param single text to put in the left column
+ */
+ protected void addOptionRow( String single ) {
+ addOptionRow( single, "" );
+ }
+
+ /**
+ * Adds a row of option help output in the left and right columns.
+ *
+ * @param left text to put in the left column
+ * @param right text to put in the right column
+ */
+ protected void addOptionRow( String left, String right ) {
+ optionRows.add( left, right );
+ }
+
+ /**
+ * Adds a single row of non-option argument help.
+ *
+ * @param single single row of non-option argument help text
+ */
+ protected void addNonOptionRow( String single ) {
+ nonOptionRows.add( single, "" );
+ }
+
+ /**
+ * Resizes the columns of all the rows to be no wider than the widest element in that column.
+ */
+ protected void fitRowsToWidth() {
+ nonOptionRows.fitToWidth();
+ optionRows.fitToWidth();
+ }
+
+ /**
+ * Produces non-option argument help.
+ *
+ * @return non-option argument help
+ */
+ protected String nonOptionOutput() {
+ return nonOptionRows.render();
+ }
+
+ /**
+ * Produces help for options and their descriptions.
+ *
+ * @return option help
+ */
+ protected String optionOutput() {
+ return optionRows.render();
+ }
+
+ /**
+ * <p>Produces help output for an entire set of options and non-option arguments.</p>
+ *
+ * <p>This implementation concatenates:</p>
+ * <ul>
+ * <li>the result of {@link #nonOptionOutput()}</li>
+ * <li>if there is non-option output, a line separator</li>
+ * <li>the result of {@link #optionOutput()}</li>
+ * </ul>
+ *
+ * @return help output for entire set of options and non-option arguments
+ */
+ protected String formattedHelpOutput() {
+ StringBuilder formatted = new StringBuilder();
+ String nonOptionDisplay = nonOptionOutput();
+ if ( !Strings.isNullOrEmpty( nonOptionDisplay ) )
+ formatted.append( nonOptionDisplay ).append( LINE_SEPARATOR );
+ formatted.append( optionOutput() );
+
+ return formatted.toString();
+ }
+
+ /**
+ * <p>Adds rows of help output for the given options.</p>
+ *
+ * <p>This implementation:</p>
+ * <ul>
+ * <li>Calls {@link #addNonOptionsDescription(java.util.Collection)} with the options as the argument</li>
+ * <li>If there are no options, calls {@link #addOptionRow(String)} with an argument that indicates
+ * that no options are specified.</li>
+ * <li>Otherwise, calls {@link #addHeaders(java.util.Collection)} with the options as the argument,
+ * followed by {@link #addOptions(java.util.Collection)} with the options as the argument.</li>
+ * <li>Calls {@link #fitRowsToWidth()}.</li>
+ * </ul>
+ *
+ * @param options descriptors for the configured options of a parser
+ */
+ protected void addRows( Collection<? extends OptionDescriptor> options ) {
+ addNonOptionsDescription( options );
+
+ if ( options.isEmpty() )
+ addOptionRow( message( "no.options.specified" ) );
+ else {
+ addHeaders( options );
+ addOptions( options );
+ }
+
+ fitRowsToWidth();
+ }
+
+ /**
+ * <p>Adds non-option arguments descriptions to the help output.</p>
+ *
+ * <p>This implementation:</p>
+ * <ul>
+ * <li>{@linkplain #findAndRemoveNonOptionsSpec(java.util.Collection) Finds and removes the non-option
+ * arguments descriptor}</li>
+ * <li>{@linkplain #shouldShowNonOptionArgumentDisplay(OptionDescriptor) Decides whether there is
+ * anything to show for non-option arguments}</li>
+ * <li>If there is, {@linkplain #addNonOptionRow(String) adds a header row} and
+ * {@linkplain #addNonOptionRow(String) adds a}
+ * {@linkplain #createNonOptionArgumentsDisplay(OptionDescriptor) non-option arguments description} </li>
+ * </ul>
+ *
+ * @param options descriptors for the configured options of a parser
+ */
+ protected void addNonOptionsDescription( Collection<? extends OptionDescriptor> options ) {
+ OptionDescriptor nonOptions = findAndRemoveNonOptionsSpec( options );
+ if ( shouldShowNonOptionArgumentDisplay( nonOptions ) ) {
+ addNonOptionRow( message( "non.option.arguments.header" ) );
+ addNonOptionRow( createNonOptionArgumentsDisplay( nonOptions ) );
+ }
+ }
+
+ /**
+ * <p>Decides whether or not to show a non-option arguments help.</p>
+ *
+ * <p>This implementation responds with {@code true} if the non-option descriptor has a non-{@code null},
+ * non-empty value for any of {@link OptionDescriptor#description()},
+ * {@link OptionDescriptor#argumentTypeIndicator()}, or {@link OptionDescriptor#argumentDescription()}.</p>
+ *
+ * @param nonOptionDescriptor non-option argument descriptor
+ * @return {@code true} if non-options argument help should be shown
+ */
+ protected boolean shouldShowNonOptionArgumentDisplay( OptionDescriptor nonOptionDescriptor ) {
+ return !Strings.isNullOrEmpty( nonOptionDescriptor.description() )
+ || !Strings.isNullOrEmpty( nonOptionDescriptor.argumentTypeIndicator() )
+ || !Strings.isNullOrEmpty( nonOptionDescriptor.argumentDescription() );
+ }
+
+ /**
+ * <p>Creates a non-options argument help string.</p>
+ *
+ * <p>This implementation creates an empty string buffer and calls
+ * {@link #maybeAppendOptionInfo(StringBuilder, OptionDescriptor)}
+ * and {@link #maybeAppendNonOptionsDescription(StringBuilder, OptionDescriptor)}, passing them the
+ * buffer and the non-option arguments descriptor.</p>
+ *
+ * @param nonOptionDescriptor non-option argument descriptor
+ * @return help string for non-options
+ */
+ protected String createNonOptionArgumentsDisplay( OptionDescriptor nonOptionDescriptor ) {
+ StringBuilder buffer = new StringBuilder();
+ maybeAppendOptionInfo( buffer, nonOptionDescriptor );
+ maybeAppendNonOptionsDescription( buffer, nonOptionDescriptor );
+
+ return buffer.toString();
+ }
+
+ /**
+ * <p>Appends help for the given non-option arguments descriptor to the given buffer.</p>
+ *
+ * <p>This implementation appends {@code " -- "} if the buffer has text in it and the non-option arguments
+ * descriptor has a {@link OptionDescriptor#description()}; followed by the
+ * {@link OptionDescriptor#description()}.</p>
+ *
+ * @param buffer string buffer
+ * @param nonOptions non-option arguments descriptor
+ */
+ protected void maybeAppendNonOptionsDescription( StringBuilder buffer, OptionDescriptor nonOptions ) {
+ buffer.append( buffer.length() > 0 && !Strings.isNullOrEmpty( nonOptions.description() ) ? " -- " : "" )
+ .append( nonOptions.description() );
+ }
+
+ /**
+ * Finds the non-option arguments descriptor in the given collection, removes it, and returns it.
+ *
+ * @param options descriptors for the configured options of a parser
+ * @return the non-option arguments descriptor
+ */
+ protected OptionDescriptor findAndRemoveNonOptionsSpec( Collection<? extends OptionDescriptor> options ) {
+ for ( Iterator<? extends OptionDescriptor> it = options.iterator(); it.hasNext(); ) {
+ OptionDescriptor next = it.next();
+ if ( next.representsNonOptions() ) {
+ it.remove();
+ return next;
+ }
+ }
+
+ throw new AssertionError( "no non-options argument spec" );
+ }
+
+ /**
+ * <p>Adds help row headers for option help columns.</p>
+ *
+ * <p>This implementation uses the headers {@code "Option"} and {@code "Description"}. If the options contain
+ * a "required" option, the {@code "Option"} header looks like {@code "Option (* = required)}. Both headers
+ * are "underlined" using {@code "-"}.</p>
+ *
+ * @param options descriptors for the configured options of a parser
+ */
+ protected void addHeaders( Collection<? extends OptionDescriptor> options ) {
+ if ( hasRequiredOption( options ) ) {
+ addOptionRow( message( "option.header.with.required.indicator" ), message( "description.header" ) );
+ addOptionRow( message( "option.divider.with.required.indicator" ), message( "description.divider" ) );
+ } else {
+ addOptionRow( message( "option.header" ), message( "description.header" ) );
+ addOptionRow( message( "option.divider" ), message( "description.divider" ) );
+ }
+ }
+
+ /**
+ * Tells whether the given option descriptors contain a "required" option.
+ *
+ * @param options descriptors for the configured options of a parser
+ * @return {@code true} if at least one of the options is "required"
+ */
+ protected final boolean hasRequiredOption( Collection<? extends OptionDescriptor> options ) {
+ for ( OptionDescriptor each : options ) {
+ if ( each.isRequired() )
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * <p>Adds help rows for the given options.</p>
+ *
+ * <p>This implementation loops over the given options, and for each, calls {@link #addOptionRow(String, String)}
+ * using the results of {@link #createOptionDisplay(OptionDescriptor)} and
+ * {@link #createDescriptionDisplay(OptionDescriptor)}, respectively, as arguments.</p>
+ *
+ * @param options descriptors for the configured options of a parser
+ */
+ protected void addOptions( Collection<? extends OptionDescriptor> options ) {
+ for ( OptionDescriptor each : options ) {
+ if ( !each.representsNonOptions() )
+ addOptionRow( createOptionDisplay( each ), createDescriptionDisplay( each ) );
+ }
+ }
+
+ /**
+ * <p>Creates a string for how the given option descriptor is to be represented in help.</p>
+ *
+ * <p>This implementation gives a string consisting of the concatenation of:</p>
+ * <ul>
+ * <li>{@code "* "} for "required" options, otherwise {@code ""}</li>
+ * <li>For each of the {@link OptionDescriptor#options()} of the descriptor, separated by {@code ", "}:
+ * <ul>
+ * <li>{@link #optionLeader(String)} of the option</li>
+ * <li>the option</li>
+ * </ul>
+ * </li>
+ * <li>the result of {@link #maybeAppendOptionInfo(StringBuilder, OptionDescriptor)}</li>
+ * </ul>
+ *
+ * @param descriptor a descriptor for a configured option of a parser
+ * @return help string
+ */
+ protected String createOptionDisplay( OptionDescriptor descriptor ) {
+ StringBuilder buffer = new StringBuilder( descriptor.isRequired() ? "* " : "" );
+
+ for ( Iterator<String> i = descriptor.options().iterator(); i.hasNext(); ) {
+ String option = i.next();
+ buffer.append( optionLeader( option ) );
+ buffer.append( option );
+
+ if ( i.hasNext() )
+ buffer.append( ", " );
+ }
+
+ maybeAppendOptionInfo( buffer, descriptor );
+
+ return buffer.toString();
+ }
+
+ /**
+ * <p>Gives a string that represents the given option's "option leader" in help.</p>
+ *
+ * <p>This implementation answers with {@code "--"} for options of length greater than one; otherwise answers
+ * with {@code "-"}.</p>
+ *
+ * @param option a string option
+ * @return an "option leader" string
+ */
+ protected String optionLeader( String option ) {
+ return option.length() > 1 ? DOUBLE_HYPHEN : HYPHEN;
+ }
+
+ /**
+ * <p>Appends additional info about the given option to the given buffer.</p>
+ *
+ * <p>This implementation:</p>
+ * <ul>
+ * <li>calls {@link #extractTypeIndicator(OptionDescriptor)} for the descriptor</li>
+ * <li>calls {@link joptsimple.OptionDescriptor#argumentDescription()} for the descriptor</li>
+ * <li>if either of the above is present, calls
+ * {@link #appendOptionHelp(StringBuilder, String, String, boolean)}</li>
+ * </ul>
+ *
+ * @param buffer string buffer
+ * @param descriptor a descriptor for a configured option of a parser
+ */
+ protected void maybeAppendOptionInfo( StringBuilder buffer, OptionDescriptor descriptor ) {
+ String indicator = extractTypeIndicator( descriptor );
+ String description = descriptor.argumentDescription();
+ if ( descriptor.acceptsArguments()
+ || !isNullOrEmpty( description )
+ || descriptor.representsNonOptions() ) {
+
+ appendOptionHelp( buffer, indicator, description, descriptor.requiresArgument() );
+ }
+ }
+
+ /**
+ * <p>Gives an indicator of the type of arguments of the option described by the given descriptor,
+ * for use in help.</p>
+ *
+ * <p>This implementation asks for the {@link OptionDescriptor#argumentTypeIndicator()} of the given
+ * descriptor, and if it is present and not {@code "java.lang.String"}, parses it as a fully qualified
+ * class name and returns the base name of that class; otherwise returns {@code "String"}.</p>
+ *
+ * @param descriptor a descriptor for a configured option of a parser
+ * @return type indicator text
+ */
+ protected String extractTypeIndicator( OptionDescriptor descriptor ) {
+ String indicator = descriptor.argumentTypeIndicator();
+
+ if ( !isNullOrEmpty( indicator ) && !String.class.getName().equals( indicator ) )
+ return shortNameOf( indicator );
+
+ return "String";
+ }
+
+ /**
+ * <p>Appends info about an option's argument to the given buffer.</p>
+ *
+ * <p>This implementation calls {@link #appendTypeIndicator(StringBuilder, String, String, char, char)} with
+ * the surrounding characters {@code '<'} and {@code '>'} for options with {@code required} arguments, and
+ * with the surrounding characters {@code '['} and {@code ']'} for options with optional arguments.</p>
+ *
+ * @param buffer string buffer
+ * @param typeIndicator type indicator
+ * @param description type description
+ * @param required indicator of "required"-ness of the argument of the option
+ */
+ protected void appendOptionHelp( StringBuilder buffer, String typeIndicator, String description,
+ boolean required ) {
+ if ( required )
+ appendTypeIndicator( buffer, typeIndicator, description, '<', '>' );
+ else
+ appendTypeIndicator( buffer, typeIndicator, description, '[', ']' );
+ }
+
+ /**
+ * <p>Appends a type indicator for an option's argument to the given buffer.</p>
+ *
+ * <p>This implementation appends, in order:</p>
+ * <ul>
+ * <li>{@code ' '}</li>
+ * <li>{@code start}</li>
+ * <li>the type indicator, if not {@code null}</li>
+ * <li>if the description is present, then {@code ": "} plus the description if the type indicator is
+ * present; otherwise the description only</li>
+ * <li>{@code end}</li>
+ * </ul>
+ *
+ * @param buffer string buffer
+ * @param typeIndicator type indicator
+ * @param description type description
+ * @param start starting character
+ * @param end ending character
+ */
+ protected void appendTypeIndicator( StringBuilder buffer, String typeIndicator, String description,
+ char start, char end ) {
+ buffer.append( ' ' ).append( start );
+ if ( typeIndicator != null )
+ buffer.append( typeIndicator );
+
+ if ( !Strings.isNullOrEmpty( description ) ) {
+ if ( typeIndicator != null )
+ buffer.append( ": " );
+
+ buffer.append( description );
+ }
+
+ buffer.append( end );
+ }
+
+ /**
+ * <p>Gives a string representing a description of the option with the given descriptor.</p>
+ *
+ * <p>This implementation:</p>
+ * <ul>
+ * <li>Asks for the descriptor's {@link OptionDescriptor#defaultValues()}</li>
+ * <li>If they're not present, answers the descriptor's {@link OptionDescriptor#description()}.</li>
+ * <li>If they are present, concatenates and returns:
+ * <ul>
+ * <li>the descriptor's {@link OptionDescriptor#description()}</li>
+ * <li>{@code ' '}</li>
+ * <li>{@code "default: "} plus the result of {@link #createDefaultValuesDisplay(java.util.List)},
+ * surrounded by parentheses</li>
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * @param descriptor a descriptor for a configured option of a parser
+ * @return display text for the option's description
+ */
+ protected String createDescriptionDisplay( OptionDescriptor descriptor ) {
+ List<?> defaultValues = descriptor.defaultValues();
+ if ( defaultValues.isEmpty() )
+ return descriptor.description();
+
+ String defaultValuesDisplay = createDefaultValuesDisplay( defaultValues );
+ return ( descriptor.description()
+ + ' '
+ + surround( message( "default.value.header" ) + ' ' + defaultValuesDisplay, '(', ')' )
+ ).trim();
+ }
+
+ /**
+ * <p>Gives a display string for the default values of an option's argument.</p>
+ *
+ * <p>This implementation gives the {@link Object#toString()} of the first value if there is only one value,
+ * otherwise gives the {@link Object#toString()} of the whole list.</p>
+ *
+ * @param defaultValues some default values for a given option's argument
+ * @return a display string for those default values
+ */
+ protected String createDefaultValuesDisplay( List<?> defaultValues ) {
+ return defaultValues.size() == 1 ? defaultValues.get( 0 ).toString() : defaultValues.toString();
+ }
+
+ /**
+ * <p>Looks up and gives a resource bundle message.</p>
+ *
+ * <p>This implementation looks in the bundle {@code "joptsimple.HelpFormatterMessages"} in the default
+ * locale, using a key that is the concatenation of this class's fully qualified name, {@code '.'},
+ * and the given key suffix, formats the corresponding value using the given arguments, and returns
+ * the result.</p>
+ *
+ * @param keySuffix suffix to use when looking up the bundle message
+ * @param args arguments to fill in the message template with
+ * @return a formatted localized message
+ */
+ protected String message( String keySuffix, Object... args ) {
+ return Messages.message(
+ Locale.getDefault(),
+ "joptsimple.HelpFormatterMessages",
+ BuiltinHelpFormatter.class,
+ keySuffix,
+ args );
+ }
+}