Copyright (C) 2010 the original author or authors. See the notice.md file distributed with this work for additional information regarding copyright ownership. Licensed 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.
/** * Copyright (C) 2010 the original author or authors. * See the notice.md file distributed with this work for additional * information regarding copyright ownership. * * Licensed 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 com.beust.jcommander; import com.beust.jcommander.internal.Lists; import java.util.*; import java.util.ResourceBundle;
The default usage formatter.
/** * The default usage formatter. */
public class DefaultUsageFormatter implements IUsageFormatter { private final JCommander commander; public DefaultUsageFormatter(JCommander commander) { this.commander = commander; }
Prints the usage to JCommander.getConsole() on the underlying commander instance.
/** * Prints the usage to {@link JCommander#getConsole()} on the underlying commander instance. */
public final void usage(String commandName) { StringBuilder sb = new StringBuilder(); usage(commandName, sb); commander.getConsole().println(sb.toString()); }
Store the usage for the argument command in the argument string builder.
/** * Store the usage for the argument command in the argument string builder. */
public final void usage(String commandName, StringBuilder out) { usage(commandName, out, ""); }
Store the usage in the argument string builder.
/** * Store the usage in the argument string builder. */
public final void usage(StringBuilder out) { usage(out, ""); }
Store the usage for the command in the argument string builder, indenting every line with the value of indent.
/** * Store the usage for the command in the argument string builder, indenting every line with the * value of indent. */
public final void usage(String commandName, StringBuilder out, String indent) { String description = getCommandDescription(commandName); JCommander jc = commander.findCommandByAlias(commandName); if (description != null) { out.append(indent).append(description); out.append("\n"); } jc.getUsageFormatter().usage(out, indent); }
Stores the usage in the argument string builder, with the argument indentation. This works by appending each portion of the help in the following order. Their outputs can be modified by overriding them in a subclass of this class.
/** * Stores the usage in the argument string builder, with the argument indentation. This works by appending * each portion of the help in the following order. Their outputs can be modified by overriding them in a * subclass of this class. * * <ul> * <li>Main line - {@link #appendMainLine(StringBuilder, boolean, boolean, int, String)}</li> * <li>Parameters - {@link #appendAllParametersDetails(StringBuilder, int, String, List)}</li> * <li>Commands - {@link #appendCommands(StringBuilder, int, int, String)}</li> * </ul> */
public void usage(StringBuilder out, String indent) { if (commander.getDescriptions() == null) { commander.createDescriptions(); } boolean hasCommands = !commander.getCommands().isEmpty(); boolean hasOptions = !commander.getDescriptions().isEmpty(); // Indentation constants final int descriptionIndent = 6; final int indentCount = indent.length() + descriptionIndent; // Append first line (aka main line) of the usage appendMainLine(out, hasOptions, hasCommands, indentCount, indent); // Align the descriptions at the "longestName" column int longestName = 0; List<ParameterDescription> sortedParameters = Lists.newArrayList(); for (ParameterDescription pd : commander.getFields().values()) { if (!pd.getParameter().hidden()) { sortedParameters.add(pd); // + to have an extra space between the name and the description int length = pd.getNames().length() + 2; if (length > longestName) { longestName = length; } } } // Sort the options sortedParameters.sort(commander.getParameterDescriptionComparator()); // Append all the parameter names and descriptions appendAllParametersDetails(out, indentCount, indent, sortedParameters); // Append commands if they were specified if (hasCommands) { appendCommands(out, indentCount, descriptionIndent, indent); } }
Appends the main line segment of the usage to the argument string builder, indenting every line with indentCount-many indent.
Params:
  • out – the builder to append to
  • hasOptions – if the options section should be appended
  • hasCommands – if the comments section should be appended
  • indentCount – the amount of indentation to apply
  • indent – the indentation
/** * Appends the main line segment of the usage to the argument string builder, indenting every * line with indentCount-many indent. * * @param out the builder to append to * @param hasOptions if the options section should be appended * @param hasCommands if the comments section should be appended * @param indentCount the amount of indentation to apply * @param indent the indentation */
public void appendMainLine(StringBuilder out, boolean hasOptions, boolean hasCommands, int indentCount, String indent) { String programName = commander.getProgramDisplayName() != null ? commander.getProgramDisplayName() : "<main class>"; StringBuilder mainLine = new StringBuilder(); mainLine.append(indent).append("Usage: ").append(programName); if (hasOptions) { mainLine.append(" [options]"); } if (hasCommands) { mainLine.append(indent).append(" [command] [command options]"); } if (commander.getMainParameter() != null && commander.getMainParameter().getDescription() != null) { mainLine.append(" ").append(commander.getMainParameter().getDescription().getDescription()); } wrapDescription(out, indentCount, mainLine.toString()); out.append("\n"); }
Appends the details of all parameters in the given order to the argument string builder, indenting every line with indentCount-many indent.
Params:
  • out – the builder to append to
  • indentCount – the amount of indentation to apply
  • indent – the indentation
  • sortedParameters – the parameters to append to the builder
/** * Appends the details of all parameters in the given order to the argument string builder, indenting every * line with indentCount-many indent. * * @param out the builder to append to * @param indentCount the amount of indentation to apply * @param indent the indentation * @param sortedParameters the parameters to append to the builder */
public void appendAllParametersDetails(StringBuilder out, int indentCount, String indent, List<ParameterDescription> sortedParameters) { if (sortedParameters.size() > 0) { out.append(indent).append(" Options:\n"); } for (ParameterDescription pd : sortedParameters) { WrappedParameter parameter = pd.getParameter(); String description = pd.getDescription(); boolean hasDescription = !description.isEmpty(); // First line, command name out.append(indent) .append(" ") .append(parameter.required() ? "* " : " ") .append(pd.getNames()) .append("\n"); if (hasDescription) { wrapDescription(out, indentCount, s(indentCount) + description); } Object def = pd.getDefault(); if (pd.isDynamicParameter()) { String syntax = "Syntax: " + parameter.names()[0] + "key" + parameter.getAssignment() + "value"; if (hasDescription) { out.append(newLineAndIndent(indentCount)); } else { out.append(s(indentCount)); } out.append(syntax); } if (def != null && !pd.isHelp()) { String displayedDef = Strings.isStringEmpty(def.toString()) ? "<empty string>" : def.toString(); String defaultText = "Default: " + (parameter.password() ? "********" : displayedDef); if (hasDescription) { out.append(newLineAndIndent(indentCount)); } else { out.append(s(indentCount)); } out.append(defaultText); } Class<?> type = pd.getParameterized().getType(); if (type.isEnum()) { String valueList = EnumSet.allOf((Class<? extends Enum>) type).toString(); String possibleValues = "Possible Values: " + valueList; // Prevent duplicate values list, since it is set as 'Options: [values]' if the description // of an enum field is empty in ParameterDescription#init(..) if (!description.contains("Options: " + valueList)) { if (hasDescription) { out.append(newLineAndIndent(indentCount)); } else { out.append(s(indentCount)); } out.append(possibleValues); } } out.append("\n"); } }
Appends the details of all commands to the argument string builder, indenting every line with indentCount-many indent. The commands are obtained from calling JCommander.getRawCommands() and the commands are resolved using JCommander.findCommandByAlias(String) on the underlying commander instance.
Params:
  • out – the builder to append to
  • indentCount – the amount of indentation to apply
  • descriptionIndent – the indentation for the description
  • indent – the indentation
/** * Appends the details of all commands to the argument string builder, indenting every line with * indentCount-many indent. The commands are obtained from calling * {@link JCommander#getRawCommands()} and the commands are resolved using * {@link JCommander#findCommandByAlias(String)} on the underlying commander instance. * * @param out the builder to append to * @param indentCount the amount of indentation to apply * @param descriptionIndent the indentation for the description * @param indent the indentation */
public void appendCommands(StringBuilder out, int indentCount, int descriptionIndent, String indent) { out.append(indent + " Commands:\n"); // The magic value 3 is the number of spaces between the name of the option and its description for (Map.Entry<JCommander.ProgramName, JCommander> commands : commander.getRawCommands().entrySet()) { Object arg = commands.getValue().getObjects().get(0); Parameters p = arg.getClass().getAnnotation(Parameters.class); if (p == null || !p.hidden()) { JCommander.ProgramName progName = commands.getKey(); String dispName = progName.getDisplayName(); String description = indent + s(4) + dispName + s(6) + getCommandDescription(progName.getName()); wrapDescription(out, indentCount + descriptionIndent, description); out.append("\n"); // Options for this command JCommander jc = commander.findCommandByAlias(progName.getName()); jc.getUsageFormatter().usage(out, indent + s(6)); out.append("\n"); } } }
Returns the description of the command corresponding to the argument command name. The commands are resolved by calling JCommander.findCommandByAlias(String), and the default resource bundle used from JCommander.getBundle() on the underlying commander instance.
Params:
  • commandName – the name of the command to get the description for
Returns:the description of the command.
/** * Returns the description of the command corresponding to the argument command name. The commands are resolved * by calling {@link JCommander#findCommandByAlias(String)}, and the default resource bundle used from * {@link JCommander#getBundle()} on the underlying commander instance. * * @param commandName the name of the command to get the description for * @return the description of the command. */
public String getCommandDescription(String commandName) { JCommander jc = commander.findCommandByAlias(commandName); if (jc == null) { throw new ParameterException("Asking description for unknown command: " + commandName); } Object arg = jc.getObjects().get(0); Parameters p = arg.getClass().getAnnotation(Parameters.class); java.util.ResourceBundle bundle; String result = null; if (p != null) { result = p.commandDescription(); String bundleName = p.resourceBundle(); if (!bundleName.isEmpty()) { bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); } else { bundle = commander.getBundle(); } if (bundle != null) { String descriptionKey = p.commandDescriptionKey(); if (!descriptionKey.isEmpty()) { result = getI18nString(bundle, descriptionKey, p.commandDescription()); } } } return result; }
Wrap a potentially long line to the value obtained by calling JCommander.getColumnSize() on the underlying commander instance.
Params:
  • out – the output
  • indent – the indentation in spaces for lines after the first line.
  • currentLineIndent – the length of the indentation of the initial line
  • description – the text to wrap. No extra spaces are inserted before description. If the first line needs to be indented prepend the correct number of spaces to description.
/** * Wrap a potentially long line to the value obtained by calling {@link JCommander#getColumnSize()} on the * underlying commander instance. * * @param out the output * @param indent the indentation in spaces for lines after the first line. * @param currentLineIndent the length of the indentation of the initial line * @param description the text to wrap. No extra spaces are inserted before {@code * description}. If the first line needs to be indented prepend the * correct number of spaces to {@code description}. */
public void wrapDescription(StringBuilder out, int indent, int currentLineIndent, String description) { int max = commander.getColumnSize(); String[] words = description.split(" "); int current = currentLineIndent; for (int i = 0; i < words.length; i++) { String word = words[i]; if (word.length() > max || current + 1 + word.length() <= max) { out.append(word); current += word.length(); if (i != words.length - 1) { out.append(" "); current++; } } else { out.append("\n").append(s(indent)).append(word).append(" "); current = indent + word.length() + 1; } } }
Wrap a potentially long line to { @link #commander#getColumnSize()}.
Params:
  • out – the output
  • indent – the indentation in spaces for lines after the first line.
  • description – the text to wrap. No extra spaces are inserted before description. If the first line needs to be indented prepend the correct number of spaces to description.
See Also:
/** * Wrap a potentially long line to { @link #commander#getColumnSize()}. * * @param out the output * @param indent the indentation in spaces for lines after the first line. * @param description the text to wrap. No extra spaces are inserted before {@code * description}. If the first line needs to be indented prepend the * correct number of spaces to {@code description}. * @see #wrapDescription(StringBuilder, int, int, String) */
public void wrapDescription(StringBuilder out, int indent, String description) { wrapDescription(out, indent, 0, description); }
Returns the internationalized version of the string if available, otherwise it returns def.
Returns:the internationalized version of the string if available, otherwise it returns def
/** * Returns the internationalized version of the string if available, otherwise it returns def. * * @return the internationalized version of the string if available, otherwise it returns def */
public static String getI18nString(ResourceBundle bundle, String key, String def) { String s = bundle != null ? bundle.getString(key) : null; return s != null ? s : def; }
Returns count-many spaces.
Returns:count-many spaces
/** * Returns count-many spaces. * * @return count-many spaces */
public static String s(int count) { StringBuilder result = new StringBuilder(); for (int i = 0; i < count; i++) { result.append(" "); } return result.toString(); }
Returns new line followed by indent-many spaces.
Returns:new line followed by indent-many spaces
/** * Returns new line followed by indent-many spaces. * * @return new line followed by indent-many spaces */
private static String newLineAndIndent(int indent) { return "\n" + s(indent); } }