sep = appendStringArray(pw, sep, indent, "aliases = %s", spec.aliases(), EMPTY_ARRAY); sep = append(pw, sep, indent, "mixinStandardHelpOptions = %s", spec.mixinStandardHelpOptions(), false); sep = append(pw, sep, indent, "headerHeading = \"%s\"", spec.usageMessage().headerHeading(), ""); sep = appendStringArray(pw, sep, indent, "header = %s", spec.usageMessage().header(), EMPTY_ARRAY); sep = append(pw, sep, indent, "descriptionHeading = \"%s\"", spec.usageMessage().descriptionHeading(), ""); sep = appendStringArray(pw, sep, indent, "description = %s", spec.usageMessage().description(), EMPTY_ARRAY); sep = append(pw, sep, indent, "synopsisHeading = \"%s\"", spec.usageMessage().synopsisHeading(), "Usage: "); sep = append(pw, sep, indent, "abbreviateSynopsis = %s", spec.usageMessage().abbreviateSynopsis(), false); sep = appendStringArray(pw, sep, indent, "customSynopsis = %s", spec.usageMessage().customSynopsis(), EMPTY_ARRAY); sep = append(pw, sep, indent, "optionListHeading = \"%s\"", spec.usageMessage().optionListHeading(), ""); sep = append(pw, sep, indent, "parameterListHeading = \"%s\"", spec.usageMessage().parameterListHeading(), ""); sep = append(pw, sep, indent, "commandListHeading = \"%s\"", spec.usageMessage().commandListHeading(), "Commands:%n"); sep = append(pw, sep, indent, "footerHeading = \"%s\"", spec.usageMessage().footerHeading(), ""); sep = appendStringArray(pw, sep, indent, "footer = %s", spec.usageMessage().footer(), EMPTY_ARRAY); sep = append(pw, sep, indent, "requiredOptionMarker = \'%s\'", spec.usageMessage().requiredOptionMarker(), ' '); sep = append(pw, sep, indent, "addMethodSubcommands = %s", spec.isAddMethodSubcommands(), !isCommandMethod(spec)); sep = appendSubcommandClasses(pw, sep, indent, spec.subcommands()); sep = appendStringArray(pw, sep, indent, "version = %s", spec.version(), EMPTY_ARRAY); sep = appendClassName(pw, sep, indent, "versionProvider = %s", spec.versionProvider()); sep = append(pw, sep, indent, "showDefaultValues = %s", spec.usageMessage().showDefaultValues(), false); sep = appendClassName(pw, sep, indent, "defaultValueProvider = %s", spec.defaultValueProvider()); sep = append(pw, sep, indent, "resourceBundle = \"%s\"", spec.resourceBundleBaseName(), "null"); sep = append(pw, sep, indent, "sortOptions = %s", spec.usageMessage().sortOptions(), true); sep = append(pw, sep, indent, "hidden = %s", spec.usageMessage().hidden(), false); sep = append(pw, sep, indent, "helpCommand = %s", spec.helpCommand(), false); sep = append(pw, sep, indent, "separator = \"%s\"", spec.parser().separator(), "="); sep = append(pw, sep, indent, "usageHelpWidth = %s", spec.usageMessage().width(), 80);
assertEquals("base header heading", help.headerHeading()); assertEquals("", help.optionList()); assertEquals("base option heading", help.commandSpec().usageMessage().optionListHeading()); assertEquals("", help.optionListHeading()); // because no options assertEquals("", help.parameterList()); assertEquals("base param heading", help.commandSpec().usageMessage().parameterListHeading()); assertEquals("", help.parameterListHeading()); // because no parameters assertTrue(help.commandSpec().usageMessage().abbreviateSynopsis()); assertTrue(help.commandSpec().usageMessage().showDefaultValues()); assertFalse(help.commandSpec().usageMessage().sortOptions()); assertEquals(";", help.commandSpec().parser().separator()); assertEquals('&', help.commandSpec().usageMessage().requiredOptionMarker());
assertEquals("", help.commandList()); assertEquals("", help.commandListHeading()); // empty: no commands assertEquals("subc o m m a n d s", help.commandSpec().usageMessage().commandListHeading()); assertEquals(String.format("sub description%n"), help.description()); assertEquals("sub descr heading", help.descriptionHeading()); assertEquals("", help.optionList()); assertEquals("", help.optionListHeading()); assertEquals("sub option heading", help.commandSpec().usageMessage().optionListHeading()); assertEquals("", help.parameterList()); assertEquals("", help.parameterListHeading()); assertEquals("sub param heading", help.commandSpec().usageMessage().parameterListHeading()); assertTrue(help.commandSpec().usageMessage().abbreviateSynopsis()); assertTrue(help.commandSpec().usageMessage().showDefaultValues()); assertFalse(help.commandSpec().usageMessage().sortOptions()); assertEquals(":", help.commandSpec().parser().separator()); assertEquals('%', help.commandSpec().usageMessage().requiredOptionMarker());
assertEquals("", help.commandList()); assertEquals("", help.commandListHeading()); assertEquals("c o m m a n d s", help.commandSpec().usageMessage().commandListHeading()); assertEquals(String.format("base description%n"), help.description()); assertEquals("base descr heading", help.descriptionHeading()); assertEquals("", help.optionList()); assertEquals("", help.optionListHeading()); assertEquals("base option heading", help.commandSpec().usageMessage().optionListHeading()); assertEquals("", help.parameterList()); assertEquals("", help.parameterListHeading()); assertEquals("base param heading", help.commandSpec().usageMessage().parameterListHeading()); assertEquals('&', help.commandSpec().usageMessage().requiredOptionMarker()); assertTrue(help.commandSpec().usageMessage().abbreviateSynopsis()); assertTrue(help.commandSpec().usageMessage().showDefaultValues()); assertFalse(help.commandSpec().usageMessage().sortOptions());
spec.name("the awesome util"); spec.usageMessage() .descriptionHeading("Description heading%n") .description("description line 1", "description line 2") .footerHeading("Footer heading%n") .footer("footer line 1", "footer line 2") .headerHeading("Header heading%n") .header("header line 1", "header line 2") .optionListHeading("Options%n") .parameterListHeading("Positional Parameters%n"); spec.addPositional(PositionalParamSpec.builder().description("positional param").build()); CommandLine commandLine = new CommandLine(spec);
assertArrayEquals(new String[] {"description from mixinSub"}, usage.description()); assertEquals("MixinSub Description Heading%n", usage.descriptionHeading()); assertArrayEquals(new String[] {"MixinSub Header"}, usage.header()); assertEquals("MixinSub Header Heading%n", usage.headerHeading()); assertArrayEquals(new String[] {"ReceiverSuper Footer"}, usage.footer()); assertEquals("ReceiverSuper Footer Heading%n", usage.footerHeading()); assertEquals("ReceiverSuper Option List Heading%n", usage.optionListHeading()); assertEquals("Receiver Parameter List Heading%n", usage.parameterListHeading()); assertEquals("Receiver Command List Heading%n", usage.commandListHeading()); assertEquals('#', usage.requiredOptionMarker()); assertEquals("Receiver Synopsis Heading%n", usage.synopsisHeading()); assertArrayEquals(new String[0], usage.customSynopsis());
assertArrayEquals(new String[] {"Mixin 1.0"}, commandSpec.version()); assertEquals(":", commandSpec.parser().separator()); assertArrayEquals(new String[] {"description from mixin"}, commandSpec.usageMessage().description()); assertEquals("Mixin Description Heading%n", commandSpec.usageMessage().descriptionHeading()); assertArrayEquals(new String[] {"Mixin Header"}, commandSpec.usageMessage().header()); assertEquals("Mixin Header Heading%n", commandSpec.usageMessage().headerHeading()); assertArrayEquals(new String[] {"Mixin Footer"}, commandSpec.usageMessage().footer()); assertEquals("Mixin Footer Heading%n", commandSpec.usageMessage().footerHeading()); assertEquals("Mixin Option List Heading%n", commandSpec.usageMessage().optionListHeading()); assertEquals("Mixin Parameter List Heading%n", commandSpec.usageMessage().parameterListHeading()); assertEquals("Mixin Command List Heading%n", commandSpec.usageMessage().commandListHeading()); assertEquals('%', commandSpec.usageMessage().requiredOptionMarker()); assertEquals("Mixin Synopsis Heading%n", commandSpec.usageMessage().synopsisHeading()); assertTrue("abbreviateSynopsis", commandSpec.usageMessage().abbreviateSynopsis()); assertArrayEquals(new String[] {"Mixin custom synopsis"}, commandSpec.usageMessage().customSynopsis()); assertTrue("showDefaultValues", commandSpec.usageMessage().showDefaultValues()); assertFalse("sortOptions", commandSpec.usageMessage().sortOptions());
private void verifyMixinSuperClassCommandAttributesDontOverwriteSubclassAttributes(CommandLine commandLine) throws UnsupportedEncodingException { CommandSpec commandSpec = commandLine.getCommandSpec(); assertEquals("mixmeinSub", commandSpec.name()); assertArrayEquals(new String[] {"MixinSub 1.0"}, commandSpec.version()); assertEquals("~", commandSpec.parser().separator()); assertArrayEquals(new String[] {"description from mixinSub"}, commandSpec.usageMessage().description()); assertEquals("MixinSub Description Heading%n", commandSpec.usageMessage().descriptionHeading()); assertArrayEquals(new String[] {"MixinSub Header"}, commandSpec.usageMessage().header()); assertEquals("MixinSub Header Heading%n", commandSpec.usageMessage().headerHeading()); assertArrayEquals(new String[] {"MixinSub Footer"}, commandSpec.usageMessage().footer()); assertEquals("MixinSub Footer Heading%n", commandSpec.usageMessage().footerHeading()); assertEquals("MixinSub Option List Heading%n", commandSpec.usageMessage().optionListHeading()); assertEquals("MixinSub Parameter List Heading%n", commandSpec.usageMessage().parameterListHeading()); assertEquals("MixinSub Command List Heading%n", commandSpec.usageMessage().commandListHeading()); assertEquals('#', commandSpec.usageMessage().requiredOptionMarker()); assertEquals("MixinSub Synopsis Heading%n", commandSpec.usageMessage().synopsisHeading()); assertArrayEquals(new String[] {"MixinSub custom synopsis"}, commandSpec.usageMessage().customSynopsis()); String expected = String.format("" + "MixinSub Header Heading%n" + "MixinSub Header%n" + "MixinSub Synopsis Heading%n" + "MixinSub custom synopsis%n" + "MixinSub Description Heading%n" + "description from mixinSub%n" + "MixinSub Footer Heading%n" + "MixinSub Footer%n"); assertEquals(expected, usageString(commandLine, Help.Ansi.OFF)); }
void updateFromCommand(Command cmd, CommandSpec commandSpec) { if (isNonDefault(cmd.synopsisHeading(), DEFAULT_SYNOPSIS_HEADING)) {synopsisHeading = cmd.synopsisHeading();} if (isNonDefault(cmd.commandListHeading(), DEFAULT_COMMAND_LIST_HEADING)) {commandListHeading = cmd.commandListHeading();} if (isNonDefault(cmd.requiredOptionMarker(), DEFAULT_REQUIRED_OPTION_MARKER)) {requiredOptionMarker = cmd.requiredOptionMarker();} if (isNonDefault(cmd.abbreviateSynopsis(), DEFAULT_ABBREVIATE_SYNOPSIS)) {abbreviateSynopsis = cmd.abbreviateSynopsis();} if (isNonDefault(cmd.sortOptions(), DEFAULT_SORT_OPTIONS)) {sortOptions = cmd.sortOptions();} if (isNonDefault(cmd.showDefaultValues(), DEFAULT_SHOW_DEFAULT_VALUES)) {showDefaultValues = cmd.showDefaultValues();} if (isNonDefault(cmd.hidden(), DEFAULT_HIDDEN)) {hidden = cmd.hidden();} if (isNonDefault(cmd.customSynopsis(), DEFAULT_MULTI_LINE)) {customSynopsis = cmd.customSynopsis().clone();} if (isNonDefault(cmd.description(), DEFAULT_MULTI_LINE)) {description = cmd.description().clone();} if (isNonDefault(cmd.descriptionHeading(), DEFAULT_SINGLE_VALUE)) {descriptionHeading = cmd.descriptionHeading();} if (isNonDefault(cmd.header(), DEFAULT_MULTI_LINE)) {header = cmd.header().clone();} if (isNonDefault(cmd.headerHeading(), DEFAULT_SINGLE_VALUE)) {headerHeading = cmd.headerHeading();} if (isNonDefault(cmd.footer(), DEFAULT_MULTI_LINE)) {footer = cmd.footer().clone();} if (isNonDefault(cmd.footerHeading(), DEFAULT_SINGLE_VALUE)) {footerHeading = cmd.footerHeading();} if (isNonDefault(cmd.parameterListHeading(), DEFAULT_SINGLE_VALUE)) {parameterListHeading = cmd.parameterListHeading();} if (isNonDefault(cmd.optionListHeading(), DEFAULT_SINGLE_VALUE)) {optionListHeading = cmd.optionListHeading();} if (isNonDefault(cmd.usageHelpWidth(), DEFAULT_USAGE_WIDTH)) {width(cmd.usageHelpWidth());} // validate ResourceBundle rb = empty(cmd.resourceBundle()) ? null : ResourceBundle.getBundle(cmd.resourceBundle()); if (rb != null) { messages(new Messages(commandSpec, rb)); } // else preserve superclass bundle } void initFromMixin(UsageMessageSpec mixin, CommandSpec commandSpec) {
private void verifyMixinCommandAttributesDontOverwriteReceiverAttributes(CommandLine commandLine) throws UnsupportedEncodingException { CommandSpec commandSpec = commandLine.getCommandSpec(); assertEquals("receiver", commandSpec.name()); assertArrayEquals(new String[] {"Receiver 1.0"}, commandSpec.version()); assertEquals("~", commandSpec.parser().separator()); assertArrayEquals(new String[] {"Receiver description"}, commandSpec.usageMessage().description()); assertEquals("Receiver Description Heading%n", commandSpec.usageMessage().descriptionHeading()); assertArrayEquals(new String[] {"Receiver Header"}, commandSpec.usageMessage().header()); assertEquals("Receiver Header Heading%n", commandSpec.usageMessage().headerHeading()); assertArrayEquals(new String[] {"Receiver Footer"}, commandSpec.usageMessage().footer()); assertEquals("Receiver Footer Heading%n", commandSpec.usageMessage().footerHeading()); assertEquals("Receiver Option List Heading%n", commandSpec.usageMessage().optionListHeading()); assertEquals("Receiver Parameter List Heading%n", commandSpec.usageMessage().parameterListHeading()); assertEquals("Receiver Command List Heading%n", commandSpec.usageMessage().commandListHeading()); assertEquals('#', commandSpec.usageMessage().requiredOptionMarker()); assertEquals("Receiver Synopsis Heading%n", commandSpec.usageMessage().synopsisHeading()); assertArrayEquals(new String[] {"Receiver custom synopsis"}, commandSpec.usageMessage().customSynopsis()); String expected = String.format("" + "Receiver Header Heading%n" + "Receiver Header%n" + "Receiver Synopsis Heading%n" + "Receiver custom synopsis%n" + "Receiver Description Heading%n" + "Receiver description%n" + "Receiver Footer Heading%n" + "Receiver Footer%n"); assertEquals(expected, usageString(commandLine, Help.Ansi.OFF)); }
/** Returns a 2-column list with command names and the first line of their header or (if absent) description. * @return a usage help section describing the added commands */ public String commandList() { if (subcommands().isEmpty()) { return ""; } int commandLength = maxLength(subcommands().keySet()); Help.TextTable textTable = Help.TextTable.forColumns(ansi(), new Help.Column(commandLength + 2, 2, Help.Column.Overflow.SPAN), new Help.Column(width() - (commandLength + 2), 2, Help.Column.Overflow.WRAP)); for (Map.Entry<String, Help> entry : subcommands().entrySet()) { Help help = entry.getValue(); UsageMessageSpec usage = help.commandSpec().usageMessage(); String header = !empty(usage.header()) ? usage.header()[0] : (!empty(usage.description()) ? usage.description()[0] : ""); Text[] lines = ansi().text(format(header)).splitLines(); for (int i = 0; i < lines.length; i++) { textTable.addRowValues(i == 0 ? help.commandNamesText(", ") : Ansi.EMPTY_TEXT, lines[i]); } } return textTable.toString(); } private static int maxLength(Collection<String> any) {
@Test public void testShowAbbreviatedSynopsisUsageWithCommandOption() { CommandSpec spec = CommandSpec.create(); spec.addOption(OptionSpec.builder("-h", "--help").usageHelp(true).description("show help and exit").build()); // using abbreviated synopsis spec.usageMessage().abbreviateSynopsis(true); // adding a subcommand should show "COMMAND" option to the help synopsis spec.addSubcommand("subcommand", CommandSpec.create()); CommandLine commandLine = new CommandLine(spec); String actual = usageString(commandLine, Help.Ansi.OFF); String expected = String.format("" + "Usage: <main class> [OPTIONS] [COMMAND]%n" + " -h, --help show help and exit%n" + "Commands:%n" + " subcommand%n"); assertEquals(expected, actual); }
@Test public void testHelpSubcommandRunPrintsParentUsageIfParentSet() { HelpCommand cmd = new HelpCommand(); CommandLine help = new CommandLine(cmd); CommandSpec spec = CommandSpec.create().name("parent"); spec.usageMessage().description("the parent command"); spec.addSubcommand("parent", help); new CommandLine(spec); // make sure parent spec has a CommandLine cmd.init(help, Help.Ansi.OFF, System.out, System.err); cmd.run(); String expected = String.format("" + "Usage: parent [COMMAND]%n" + "the parent command%n" + "Commands:%n" + " parent Displays help information about the specified command%n"); assertEquals(expected, this.systemOutRule.getLog()); }
void initFromMixin(UsageMessageSpec mixin, CommandSpec commandSpec) { if (initializable(synopsisHeading, mixin.synopsisHeading(), DEFAULT_SYNOPSIS_HEADING)) {synopsisHeading = mixin.synopsisHeading();} if (initializable(commandListHeading, mixin.commandListHeading(), DEFAULT_COMMAND_LIST_HEADING)) {commandListHeading = mixin.commandListHeading();} if (initializable(requiredOptionMarker, mixin.requiredOptionMarker(), DEFAULT_REQUIRED_OPTION_MARKER)) {requiredOptionMarker = mixin.requiredOptionMarker();} if (initializable(abbreviateSynopsis, mixin.abbreviateSynopsis(), DEFAULT_ABBREVIATE_SYNOPSIS)) {abbreviateSynopsis = mixin.abbreviateSynopsis();} if (initializable(sortOptions, mixin.sortOptions(), DEFAULT_SORT_OPTIONS)) {sortOptions = mixin.sortOptions();} if (initializable(showDefaultValues, mixin.showDefaultValues(), DEFAULT_SHOW_DEFAULT_VALUES)) {showDefaultValues = mixin.showDefaultValues();} if (initializable(hidden, mixin.hidden(), DEFAULT_HIDDEN)) {hidden = mixin.hidden();} if (initializable(customSynopsis, mixin.customSynopsis(), DEFAULT_MULTI_LINE)) {customSynopsis = mixin.customSynopsis().clone();} if (initializable(description, mixin.description(), DEFAULT_MULTI_LINE)) {description = mixin.description().clone();} if (initializable(descriptionHeading, mixin.descriptionHeading(), DEFAULT_SINGLE_VALUE)) {descriptionHeading = mixin.descriptionHeading();} if (initializable(header, mixin.header(), DEFAULT_MULTI_LINE)) {header = mixin.header().clone();} if (initializable(headerHeading, mixin.headerHeading(), DEFAULT_SINGLE_VALUE)) {headerHeading = mixin.headerHeading();} if (initializable(footer, mixin.footer(), DEFAULT_MULTI_LINE)) {footer = mixin.footer().clone();} if (initializable(footerHeading, mixin.footerHeading(), DEFAULT_SINGLE_VALUE)) {footerHeading = mixin.footerHeading();} if (initializable(parameterListHeading, mixin.parameterListHeading(), DEFAULT_SINGLE_VALUE)) {parameterListHeading = mixin.parameterListHeading();} if (initializable(optionListHeading, mixin.optionListHeading(), DEFAULT_SINGLE_VALUE)) {optionListHeading = mixin.optionListHeading();} if (Messages.empty(messages)) { messages(Messages.copy(commandSpec, mixin.messages())); } } void initFrom(UsageMessageSpec settings, CommandSpec commandSpec) {
@Test public void testSetResourceBundle_descriptionsFromBundle() { @Command class Noop {} CommandLine cmd = new CommandLine(new Noop()); assertNull(cmd.getResourceBundle()); assertArrayEquals(new String[0], cmd.getCommandSpec().usageMessage().header()); Locale original = Locale.getDefault(); Locale.setDefault(Locale.ENGLISH); try { ResourceBundle rb = ResourceBundle.getBundle("picocli.SharedMessages"); cmd.setResourceBundle(rb); assertArrayEquals(new String[]{"Shared header first line", "Shared header second line"}, cmd.getCommandSpec().usageMessage().header()); } finally { Locale.setDefault(original); } }
/** Sets the maximum width of the usage help message. Longer lines are wrapped. * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.</p> * @param width the maximum width of the usage help message * @see UsageMessageSpec#width(int) * @return this {@code CommandLine} object, to allow method chaining */ public CommandLine setUsageHelpWidth(int width) { getCommandSpec().usageMessage().width(width); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setUsageHelpWidth(width); } return this; }
private int width() { return commandSpec.usageMessage().width(); } /** Returns command custom synopsis as a string. A custom synopsis can be zero or more lines, and can be
@Test public void testUsageHelp_abbreviateSynopsisWithPositional() throws UnsupportedEncodingException { CommandSpec spec = CommandSpec.create(); spec.usageMessage().abbreviateSynopsis(true).requiredOptionMarker('!').sortOptions(false); spec.addOption(OptionSpec.builder("-x").required(true).description("required").build()); spec.addPositional(PositionalParamSpec.builder().arity("1").paramLabel("POSITIONAL").description("positional").build()); CommandLine commandLine = new CommandLine(spec); String actual = usageString(commandLine, Ansi.OFF); String expected = String.format("" + "Usage: <main class> [OPTIONS] POSITIONAL...%n" + "! POSITIONAL... positional%n" + "! -x required%n"); assertEquals(expected, actual); }
/** Returns the maximum width of the usage help message. The default is 80. * @see UsageMessageSpec#width() */ public int getUsageHelpWidth() { return getCommandSpec().usageMessage().width(); }
@Test public void testUsageWidthFromSystemPropertyOverridesCommandAttribute() { @Command(usageHelpWidth = 60, description = "0123456789012345678901234567890123456789012345678901234567890123456789") class App {} System.setProperty("picocli.usage.width", "123"); try { CommandLine cmd = new CommandLine(new App()); assertEquals(123, cmd.getUsageHelpWidth()); assertEquals(123, cmd.getCommandSpec().usageMessage().width()); } finally { System.clearProperty("picocli.usage.width"); } }