All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.cli.HelpFormatter Maven / Gradle / Ivy

The newest version!
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.cli;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

/** 
 * A formatter of help messages for the current command line options
 *
 * @author Slawek Zachcial
 * @author John Keyes (john at integralsource.com)
 * @version $Revision: 751120 $, $Date: 2009-03-06 14:45:57 -0800 (Fri, 06 Mar 2009) $
 */
public class HelpFormatter
{
    // --------------------------------------------------------------- Constants

    /** default number of characters per line */
    public static final int DEFAULT_WIDTH = 74;

    /** default padding to the left of each line */
    public static final int DEFAULT_LEFT_PAD = 1;

    /**
     * the number of characters of padding to be prefixed
     * to each description line
     */
    public static final int DEFAULT_DESC_PAD = 3;

    /** the string to display at the beginning of the usage statement */
    public static final String DEFAULT_SYNTAX_PREFIX = "usage: ";

    /** default prefix for shortOpts */
    public static final String DEFAULT_OPT_PREFIX = "-";

    /** default prefix for long Option */
    public static final String DEFAULT_LONG_OPT_PREFIX = "--";

    /** default name for an argument */
    public static final String DEFAULT_ARG_NAME = "arg";

    // -------------------------------------------------------------- Attributes

    /**
     * number of characters per line
     *
     * @deprecated Scope will be made private for next major version
     * - use get/setWidth methods instead.
     */
    public int defaultWidth = DEFAULT_WIDTH;

    /**
     * amount of padding to the left of each line
     *
     * @deprecated Scope will be made private for next major version
     * - use get/setLeftPadding methods instead.
     */
    public int defaultLeftPad = DEFAULT_LEFT_PAD;

    /**
     * the number of characters of padding to be prefixed
     * to each description line
     *
     * @deprecated Scope will be made private for next major version
     * - use get/setDescPadding methods instead.
     */
    public int defaultDescPad = DEFAULT_DESC_PAD;

    /**
     * the string to display at the begining of the usage statement
     *
     * @deprecated Scope will be made private for next major version
     * - use get/setSyntaxPrefix methods instead.
     */
    public String defaultSyntaxPrefix = DEFAULT_SYNTAX_PREFIX;

    /**
     * the new line string
     *
     * @deprecated Scope will be made private for next major version
     * - use get/setNewLine methods instead.
     */
    public String defaultNewLine = System.getProperty("line.separator");

    /**
     * the shortOpt prefix
     *
     * @deprecated Scope will be made private for next major version
     * - use get/setOptPrefix methods instead.
     */
    public String defaultOptPrefix = DEFAULT_OPT_PREFIX;

    /**
     * the long Opt prefix
     *
     * @deprecated Scope will be made private for next major version
     * - use get/setLongOptPrefix methods instead.
     */
    public String defaultLongOptPrefix = DEFAULT_LONG_OPT_PREFIX;

    /**
     * the name of the argument
     *
     * @deprecated Scope will be made private for next major version
     * - use get/setArgName methods instead.
     */
    public String defaultArgName = DEFAULT_ARG_NAME;

    /**
     * Comparator used to sort the options when they output in help text
     * 
     * Defaults to case-insensitive alphabetical sorting by option key
     */
    protected Comparator optionComparator = new OptionComparator();

    /**
     * Sets the 'width'.
     *
     * @param width the new value of 'width'
     */
    public void setWidth(int width)
    {
        this.defaultWidth = width;
    }

    /**
     * Returns the 'width'.
     *
     * @return the 'width'
     */
    public int getWidth()
    {
        return defaultWidth;
    }

    /**
     * Sets the 'leftPadding'.
     *
     * @param padding the new value of 'leftPadding'
     */
    public void setLeftPadding(int padding)
    {
        this.defaultLeftPad = padding;
    }

    /**
     * Returns the 'leftPadding'.
     *
     * @return the 'leftPadding'
     */
    public int getLeftPadding()
    {
        return defaultLeftPad;
    }

    /**
     * Sets the 'descPadding'.
     *
     * @param padding the new value of 'descPadding'
     */
    public void setDescPadding(int padding)
    {
        this.defaultDescPad = padding;
    }

    /**
     * Returns the 'descPadding'.
     *
     * @return the 'descPadding'
     */
    public int getDescPadding()
    {
        return defaultDescPad;
    }

    /**
     * Sets the 'syntaxPrefix'.
     *
     * @param prefix the new value of 'syntaxPrefix'
     */
    public void setSyntaxPrefix(String prefix)
    {
        this.defaultSyntaxPrefix = prefix;
    }

    /**
     * Returns the 'syntaxPrefix'.
     *
     * @return the 'syntaxPrefix'
     */
    public String getSyntaxPrefix()
    {
        return defaultSyntaxPrefix;
    }

    /**
     * Sets the 'newLine'.
     *
     * @param newline the new value of 'newLine'
     */
    public void setNewLine(String newline)
    {
        this.defaultNewLine = newline;
    }

    /**
     * Returns the 'newLine'.
     *
     * @return the 'newLine'
     */
    public String getNewLine()
    {
        return defaultNewLine;
    }

    /**
     * Sets the 'optPrefix'.
     *
     * @param prefix the new value of 'optPrefix'
     */
    public void setOptPrefix(String prefix)
    {
        this.defaultOptPrefix = prefix;
    }

    /**
     * Returns the 'optPrefix'.
     *
     * @return the 'optPrefix'
     */
    public String getOptPrefix()
    {
        return defaultOptPrefix;
    }

    /**
     * Sets the 'longOptPrefix'.
     *
     * @param prefix the new value of 'longOptPrefix'
     */
    public void setLongOptPrefix(String prefix)
    {
        this.defaultLongOptPrefix = prefix;
    }

    /**
     * Returns the 'longOptPrefix'.
     *
     * @return the 'longOptPrefix'
     */
    public String getLongOptPrefix()
    {
        return defaultLongOptPrefix;
    }

    /**
     * Sets the 'argName'.
     *
     * @param name the new value of 'argName'
     */
    public void setArgName(String name)
    {
        this.defaultArgName = name;
    }

    /**
     * Returns the 'argName'.
     *
     * @return the 'argName'
     */
    public String getArgName()
    {
        return defaultArgName;
    }

    /**
     * Comparator used to sort the options when they output in help text
     * 
     * Defaults to case-insensitive alphabetical sorting by option key
     */
    public Comparator getOptionComparator()
    {
        return optionComparator;
    }

    /**
     * Set the comparator used to sort the options when they output in help text
     * 
     * Passing in a null parameter will set the ordering to the default mode
     */
    public void setOptionComparator(Comparator comparator)
    {
        if (comparator == null)
        {
            this.optionComparator = new OptionComparator();
        }
        else
        {
            this.optionComparator = comparator;
        }
    }

    /**
     * Print the help for options with the specified
     * command line syntax.  This method prints help information to
     * System.out.
     *
     * @param cmdLineSyntax the syntax for this application
     * @param options the Options instance
     */
    public void printHelp(String cmdLineSyntax, Options options)
    {
        printHelp(defaultWidth, cmdLineSyntax, null, options, null, false);
    }

    /**
     * Print the help for options with the specified
     * command line syntax.  This method prints help information to 
     * System.out.
     *
     * @param cmdLineSyntax the syntax for this application
     * @param options the Options instance
     * @param autoUsage whether to print an automatically generated
     * usage statement
     */
    public void printHelp(String cmdLineSyntax, Options options, boolean autoUsage)
    {
        printHelp(defaultWidth, cmdLineSyntax, null, options, null, autoUsage);
    }

    /**
     * Print the help for options with the specified
     * command line syntax.  This method prints help information to
     * System.out.
     *
     * @param cmdLineSyntax the syntax for this application
     * @param header the banner to display at the begining of the help
     * @param options the Options instance
     * @param footer the banner to display at the end of the help
     */
    public void printHelp(String cmdLineSyntax, String header, Options options, String footer)
    {
        printHelp(cmdLineSyntax, header, options, footer, false);
    }

    /**
     * Print the help for options with the specified
     * command line syntax.  This method prints help information to 
     * System.out.
     *
     * @param cmdLineSyntax the syntax for this application
     * @param header the banner to display at the begining of the help
     * @param options the Options instance
     * @param footer the banner to display at the end of the help
     * @param autoUsage whether to print an automatically generated
     * usage statement
     */
    public void printHelp(String cmdLineSyntax, String header, Options options, String footer, boolean autoUsage)
    {
        printHelp(defaultWidth, cmdLineSyntax, header, options, footer, autoUsage);
    }

    /**
     * Print the help for options with the specified
     * command line syntax.  This method prints help information to
     * System.out.
     *
     * @param width the number of characters to be displayed on each line
     * @param cmdLineSyntax the syntax for this application
     * @param header the banner to display at the beginning of the help
     * @param options the Options instance
     * @param footer the banner to display at the end of the help
     */
    public void printHelp(int width, String cmdLineSyntax, String header, Options options, String footer)
    {
        printHelp(width, cmdLineSyntax, header, options, footer, false);
    }

    /**
     * Print the help for options with the specified
     * command line syntax.  This method prints help information to
     * System.out.
     *
     * @param width the number of characters to be displayed on each line
     * @param cmdLineSyntax the syntax for this application
     * @param header the banner to display at the begining of the help
     * @param options the Options instance
     * @param footer the banner to display at the end of the help
     * @param autoUsage whether to print an automatically generated 
     * usage statement
     */
    public void printHelp(int width, String cmdLineSyntax, String header,
                          Options options, String footer, boolean autoUsage)
    {
        PrintWriter pw = new PrintWriter(System.out);

        printHelp(pw, width, cmdLineSyntax, header, options, defaultLeftPad, defaultDescPad, footer, autoUsage);
        pw.flush();
    }

    /**
     * Print the help for options with the specified
     * command line syntax.
     *
     * @param pw the writer to which the help will be written
     * @param width the number of characters to be displayed on each line
     * @param cmdLineSyntax the syntax for this application
     * @param header the banner to display at the begining of the help
     * @param options the Options instance
     * @param leftPad the number of characters of padding to be prefixed
     * to each line
     * @param descPad the number of characters of padding to be prefixed
     * to each description line
     * @param footer the banner to display at the end of the help
     *
     * @throws IllegalStateException if there is no room to print a line
     */
    public void printHelp(PrintWriter pw, int width, String cmdLineSyntax, 
                          String header, Options options, int leftPad, 
                          int descPad, String footer)
    {
        printHelp(pw, width, cmdLineSyntax, header, options, leftPad, descPad, footer, false);
    }


    /**
     * Print the help for options with the specified
     * command line syntax.
     *
     * @param pw the writer to which the help will be written
     * @param width the number of characters to be displayed on each line
     * @param cmdLineSyntax the syntax for this application
     * @param header the banner to display at the begining of the help
     * @param options the Options instance
     * @param leftPad the number of characters of padding to be prefixed
     * to each line
     * @param descPad the number of characters of padding to be prefixed
     * to each description line
     * @param footer the banner to display at the end of the help
     * @param autoUsage whether to print an automatically generated
     * usage statement
     *
     * @throws IllegalStateException if there is no room to print a line
     */
    public void printHelp(PrintWriter pw, int width, String cmdLineSyntax,
                          String header, Options options, int leftPad,
                          int descPad, String footer, boolean autoUsage)
    {
        if ((cmdLineSyntax == null) || (cmdLineSyntax.length() == 0))
        {
            throw new IllegalArgumentException("cmdLineSyntax not provided");
        }

        if (autoUsage)
        {
            printUsage(pw, width, cmdLineSyntax, options);
        }
        else
        {
            printUsage(pw, width, cmdLineSyntax);
        }

        if ((header != null) && (header.trim().length() > 0))
        {
            printWrapped(pw, width, header);
        }

        printOptions(pw, width, options, leftPad, descPad);

        if ((footer != null) && (footer.trim().length() > 0))
        {
            printWrapped(pw, width, footer);
        }
    }

    /**
     * 

Prints the usage statement for the specified application.

* * @param pw The PrintWriter to print the usage statement * @param width The number of characters to display per line * @param app The application name * @param options The command line Options * */ public void printUsage(PrintWriter pw, int width, String app, Options options) { // initialise the string buffer StringBuffer buff = new StringBuffer(defaultSyntaxPrefix).append(app).append(" "); // create a list for processed option groups final Collection processedGroups = new ArrayList(); // temp variable Option option; List optList = new ArrayList(options.getOptions()); Collections.sort(optList, getOptionComparator()); // iterate over the options for (Iterator i = optList.iterator(); i.hasNext();) { // get the next Option option = (Option) i.next(); // check if the option is part of an OptionGroup OptionGroup group = options.getOptionGroup(option); // if the option is part of a group if (group != null) { // and if the group has not already been processed if (!processedGroups.contains(group)) { // add the group to the processed list processedGroups.add(group); // add the usage clause appendOptionGroup(buff, group); } // otherwise the option was displayed in the group // previously so ignore it. } // if the Option is not part of an OptionGroup else { appendOption(buff, option, option.isRequired()); } if (i.hasNext()) { buff.append(" "); } } // call printWrapped printWrapped(pw, width, buff.toString().indexOf(' ') + 1, buff.toString()); } /** * Appends the usage clause for an OptionGroup to a StringBuffer. * The clause is wrapped in square brackets if the group is required. * The display of the options is handled by appendOption * @param buff the StringBuffer to append to * @param group the group to append * @see #appendOption(StringBuffer,Option,boolean) */ private void appendOptionGroup(final StringBuffer buff, final OptionGroup group) { if (!group.isRequired()) { buff.append("["); } List optList = new ArrayList(group.getOptions()); Collections.sort(optList, getOptionComparator()); // for each option in the OptionGroup for (Iterator i = optList.iterator(); i.hasNext();) { // whether the option is required or not is handled at group level appendOption(buff, (Option) i.next(), true); if (i.hasNext()) { buff.append(" | "); } } if (!group.isRequired()) { buff.append("]"); } } /** * Appends the usage clause for an Option to a StringBuffer. * * @param buff the StringBuffer to append to * @param option the Option to append * @param required whether the Option is required or not */ private static void appendOption(final StringBuffer buff, final Option option, final boolean required) { if (!required) { buff.append("["); } if (option.getOpt() != null) { buff.append("-").append(option.getOpt()); } else { buff.append("--").append(option.getLongOpt()); } // if the Option has a value if (option.hasArg() && option.hasArgName()) { buff.append(" <").append(option.getArgName()).append(">"); } // if the Option is not a required option if (!required) { buff.append("]"); } } /** * Print the cmdLineSyntax to the specified writer, using the * specified width. * * @param pw The printWriter to write the help to * @param width The number of characters per line for the usage statement. * @param cmdLineSyntax The usage statement. */ public void printUsage(PrintWriter pw, int width, String cmdLineSyntax) { int argPos = cmdLineSyntax.indexOf(' ') + 1; printWrapped(pw, width, defaultSyntaxPrefix.length() + argPos, defaultSyntaxPrefix + cmdLineSyntax); } /** *

Print the help for the specified Options to the specified writer, * using the specified width, left padding and description padding.

* * @param pw The printWriter to write the help to * @param width The number of characters to display per line * @param options The command line Options * @param leftPad the number of characters of padding to be prefixed * to each line * @param descPad the number of characters of padding to be prefixed * to each description line */ public void printOptions(PrintWriter pw, int width, Options options, int leftPad, int descPad) { StringBuffer sb = new StringBuffer(); renderOptions(sb, width, options, leftPad, descPad); pw.println(sb.toString()); } /** * Print the specified text to the specified PrintWriter. * * @param pw The printWriter to write the help to * @param width The number of characters to display per line * @param text The text to be written to the PrintWriter */ public void printWrapped(PrintWriter pw, int width, String text) { printWrapped(pw, width, 0, text); } /** * Print the specified text to the specified PrintWriter. * * @param pw The printWriter to write the help to * @param width The number of characters to display per line * @param nextLineTabStop The position on the next line for the first tab. * @param text The text to be written to the PrintWriter */ public void printWrapped(PrintWriter pw, int width, int nextLineTabStop, String text) { StringBuffer sb = new StringBuffer(text.length()); renderWrappedText(sb, width, nextLineTabStop, text); pw.println(sb.toString()); } // --------------------------------------------------------------- Protected /** * Render the specified Options and return the rendered Options * in a StringBuffer. * * @param sb The StringBuffer to place the rendered Options into. * @param width The number of characters to display per line * @param options The command line Options * @param leftPad the number of characters of padding to be prefixed * to each line * @param descPad the number of characters of padding to be prefixed * to each description line * * @return the StringBuffer with the rendered Options contents. */ protected StringBuffer renderOptions(StringBuffer sb, int width, Options options, int leftPad, int descPad) { final String lpad = createPadding(leftPad); final String dpad = createPadding(descPad); // first create list containing only -a,--aaa where // -a is opt and --aaa is long opt; in parallel look for // the longest opt string this list will be then used to // sort options ascending int max = 0; StringBuffer optBuf; List prefixList = new ArrayList(); List optList = options.helpOptions(); Collections.sort(optList, getOptionComparator()); for (Iterator i = optList.iterator(); i.hasNext();) { Option option = (Option) i.next(); optBuf = new StringBuffer(8); if (option.getOpt() == null) { optBuf.append(lpad).append(" " + defaultLongOptPrefix).append(option.getLongOpt()); } else { optBuf.append(lpad).append(defaultOptPrefix).append(option.getOpt()); if (option.hasLongOpt()) { optBuf.append(',').append(defaultLongOptPrefix).append(option.getLongOpt()); } } if (option.hasArg()) { if (option.hasArgName()) { optBuf.append(" <").append(option.getArgName()).append(">"); } else { optBuf.append(' '); } } prefixList.add(optBuf); max = (optBuf.length() > max) ? optBuf.length() : max; } int x = 0; for (Iterator i = optList.iterator(); i.hasNext();) { Option option = (Option) i.next(); optBuf = new StringBuffer(prefixList.get(x++).toString()); if (optBuf.length() < max) { optBuf.append(createPadding(max - optBuf.length())); } optBuf.append(dpad); int nextLineTabStop = max + descPad; if (option.getDescription() != null) { optBuf.append(option.getDescription()); } renderWrappedText(sb, width, nextLineTabStop, optBuf.toString()); if (i.hasNext()) { sb.append(defaultNewLine); } } return sb; } /** * Render the specified text and return the rendered Options * in a StringBuffer. * * @param sb The StringBuffer to place the rendered text into. * @param width The number of characters to display per line * @param nextLineTabStop The position on the next line for the first tab. * @param text The text to be rendered. * * @return the StringBuffer with the rendered Options contents. */ protected StringBuffer renderWrappedText(StringBuffer sb, int width, int nextLineTabStop, String text) { int pos = findWrapPos(text, width, 0); if (pos == -1) { sb.append(rtrim(text)); return sb; } sb.append(rtrim(text.substring(0, pos))).append(defaultNewLine); if (nextLineTabStop >= width) { // stops infinite loop happening nextLineTabStop = 1; } // all following lines must be padded with nextLineTabStop space // characters final String padding = createPadding(nextLineTabStop); while (true) { text = padding + text.substring(pos).trim(); pos = findWrapPos(text, width, 0); if (pos == -1) { sb.append(text); return sb; } if ( (text.length() > width) && (pos == nextLineTabStop - 1) ) { pos = width; } sb.append(rtrim(text.substring(0, pos))).append(defaultNewLine); } } /** * Finds the next text wrap position after startPos for the * text in text with the column width width. * The wrap point is the last postion before startPos+width having a * whitespace character (space, \n, \r). * * @param text The text being searched for the wrap position * @param width width of the wrapped text * @param startPos position from which to start the lookup whitespace * character * @return postion on which the text must be wrapped or -1 if the wrap * position is at the end of the text */ protected int findWrapPos(String text, int width, int startPos) { int pos = -1; // the line ends before the max wrap pos or a new line char found if (((pos = text.indexOf('\n', startPos)) != -1 && pos <= width) || ((pos = text.indexOf('\t', startPos)) != -1 && pos <= width)) { return pos + 1; } else if (startPos + width >= text.length()) { return -1; } // look for the last whitespace character before startPos+width pos = startPos + width; char c; while ((pos >= startPos) && ((c = text.charAt(pos)) != ' ') && (c != '\n') && (c != '\r')) { --pos; } // if we found it - just return if (pos > startPos) { return pos; } // must look for the first whitespace chearacter after startPos // + width pos = startPos + width; while ((pos <= text.length()) && ((c = text.charAt(pos)) != ' ') && (c != '\n') && (c != '\r')) { ++pos; } return (pos == text.length()) ? (-1) : pos; } /** * Return a String of padding of length len. * * @param len The length of the String of padding to create. * * @return The String of padding */ protected String createPadding(int len) { StringBuffer sb = new StringBuffer(len); for (int i = 0; i < len; ++i) { sb.append(' '); } return sb.toString(); } /** * Remove the trailing whitespace from the specified String. * * @param s The String to remove the trailing padding from. * * @return The String of without the trailing padding */ protected String rtrim(String s) { if ((s == null) || (s.length() == 0)) { return s; } int pos = s.length(); while ((pos > 0) && Character.isWhitespace(s.charAt(pos - 1))) { --pos; } return s.substring(0, pos); } // ------------------------------------------------------ Package protected // ---------------------------------------------------------------- Private // ---------------------------------------------------------- Inner classes /** * This class implements the Comparator interface * for comparing Options. */ private static class OptionComparator implements Comparator { /** * Compares its two arguments for order. Returns a negative * integer, zero, or a positive integer as the first argument * is less than, equal to, or greater than the second. * * @param o1 The first Option to be compared. * @param o2 The second Option to be compared. * @return a negative integer, zero, or a positive integer as * the first argument is less than, equal to, or greater than the * second. */ public int compare(Object o1, Object o2) { Option opt1 = (Option) o1; Option opt2 = (Option) o2; return opt1.getKey().compareToIgnoreCase(opt2.getKey()); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy