github remkop/picocli v4.4.0
Picocli 4.4.0

latest releases: v4.7.5, v4.7.4, v4.7.3...
3 years ago

Picocli 4.4.0

The picocli community is pleased to announce picocli 4.4.0.

This release contains over 45 bugfixes, enhancements, and new features.

A major new feature in this release is support for abbreviated options and subcommands. When abbreviations are enabled, users can specify the initial letter(s) of the first "component" and optionally of one or more subsequent components of an option or subcommand name. "Components" are parts of a name, separated by - dash characters or by upper/lower case. So for example, both --CamelCase and --kebab-case have two components. For details see the New and Noteworthy section below.

Another important change are parser fixes and improvements: the parser will no longer assign values that match an option name to options that take a parameter, unless the value is in quotes. Also, values that resemble, but not exactly match, option names are now treated more consistently and parser behaviour for such values is configurable.

Also worth hightlighting: from this release, the ManPageGenerator tool can be used as a subcommand in your application.

There are many more improvements in this release: it is now easier to customize the usage help message, there are JANSI fixes, and other bugfixes and enhancements. See the Fixed Issues list for details.

This is the seventy-first public release.
Picocli follows semantic versioning.

Table of Contents

  • New and noteworthy
    • Abbreviated Options and Subcommands
    • Parser Fixes and Improvements
    • ManPageGenerator as Subcommand in Your App
  • Fixed issues
  • Deprecations
  • Potential breaking changes

New and Noteworthy

Abbreviated Options and Subcommands

Since picocli 4.4, the parser can recognize abbreviated options and subcommands.
This needs to be enabled explicitly with CommandLine::setAbbreviatedOptionsAllowed and CommandLine::setAbbreviatedSubcommandsAllowed.

Recognized Abbreviations

When abbreviations are enabled, users can specify the initial letter(s) of the first component and optionally of one or more subsequent components of an option or subcommand name.

"Components" are separated by - dash characters or by case, so for example, both --CamelCase and --kebab-case have two components.

NOTE: When case sensitivity is disabled, only the - dash character can be used to separate components.

Examples of valid abbreviations:

Option or Subcommand | Recognized Abbreviations
-------------------- | ------------------------
--veryLongCamelCase  | --very, --vLCC  --vCase
--super-long-option  | --sup, --sLO, --s-l-o, --s-lon, --s-opt, --sOpt
some-long-command    | so, sLC, s-l-c, soLoCo, someCom

Ambiguous Abbreviations

When the user specifies input that can match multiple options or subcommands, the parser throws a ParameterException. When applications use the execute method, a short error message and the usage help is displayed to the user.

For example, given a command with subcommands help and hello, then ambiguous user input like hel will show this error message:

Error: 'hel' is not unique: it matches 'hello', 'help'

Abbreviated Long Options and POSIX Clustered Short Options

When an argument can match both a long option and a set of clustered short options, picocli matches the long option.

For example:

class AbbreviationsAndPosix {
    @Option(names = "-A") boolean a;
    @Option(names = "-B") boolean b;
    @Option(names = "-AaaBbb") boolean aaaBbb;
}
AbbreviationsAndPosix app = new AbbreviationsAndPosix();
new CommandLine(app).setAbbreviatedOptionsAllowed(true).parseArgs("-AB");
assertTrue(app.aaaBbb);
assertFalse(app.a);
assertFalse(app.b);

When abbreviated options are enabled, user input -AB will match the long -AaaBbb option, but not the -A and -B options.

Parser Fixes and Improvements

Option Names as Option Values

Options that take a parameter previously were able to take option names as the parameter value. From this release, this is no longer possible. The parser will no longer assign values that match an option name to an option, unless the value is in quotes. For example:

class App {
    @Option(names = "-x") String x;
    @Option(names = "-y") String y;

    public static void main(String... args) {
        App app = new App();
        new CommandLine(app).setTrimQuotes(true).parseArgs(args);
        System.out.printf("x='%s', y='%s'%n", app.x, app.y);
    }
}

In previous versions of picocli, the above command would accept input -x -y, and the value -y would be assigned to the x String field. From this release, the above input will be rejected with an error message indicating that the -x option requires a parameter.

If it is necessary to accept values that match option names, these values need to be quoted. For example:

java App -x="-y"

This will print the following output:

x='-y', y='null'

Vararg Positional Parameters No Longer Consume Unmatched Options

Vararg positional arguments no longer consume unmatched options unless configured to do so. For example:

class App {
    @Parameters(arity = "*") String[] positionals;
}

In previous versions of picocli, the parser behaviour was not consistent:

  • input -z 123 would be rejected with error "Unmatched argument: '-z'
  • input 123 -z would be accepted and the positionals String array would contain two values, 123 and -z

(Note that this problem only occurred with multi-value positional parameters defined with variable arity: arity = "*".)

From this release, both of the above input sequences will be rejected with an error message indicating that -z is an unknown option. As before, to accept such values as positional parameters, call CommandLine::setUnmatchedOptionsArePositionalParams with true.

Configure Whether Options Should Consume Unknown Options

By default, options accept parameter values that "resemble" (but don't exactly match) an option.

This release introduces a CommandLine::setUnmatchedOptionsAllowedAsOptionParameters method that makes it possible to configure the parser to reject values that resemble options as option parameters. Setting it to false will result in values resembling option names being rejected as option values.

For example:

class App {
    @Option(names = "-x") String x;
}

By default, a value like -z, which resembles an option, is accepted as the parameter for -x:

App app = new App();
new CommandLine(app).parseArgs("-x", "-z");
assertEquals("-z", app.x);

After setting the unmatchedOptionsAllowedAsOptionParameters parser option to false, values resembling an option are rejected as parameter for -x:

new CommandLine(new App())
        .setUnmatchedOptionsAllowedAsOptionParameters(false)
        .parseArgs("-x", "-z");

This will throw an UnmatchedArgumentException with message:

"Unknown option '-z'; Expected parameter for option '-x' but found '-z'"

NOTE: Negative numbers are not considered to be unknown options, so even when unmatchedOptionsAllowedAsOptionParameters is set to false, option parameters like -123, -NaN, -Infinity, -#ABC and -0xCAFEBABE will not be rejected for resembling but not matching an option name.

ManPageGenerator as Subcommand in Your App

From picocli 4.4, the ManPageGenerator tool can be used as a subcommand in your application, with the usual syntax:

import picocli.codegen.docgen.manpage.ManPageGenerator;

@Command(subcommands = ManPageGenerator.class)
...

To use the ManPageGenerator tool as a subcommand, you will need the picocli-codegen jar in your classpath.

Fixed issues

  • [#10][#732][#1047] API: Support abbreviated options and commands. Thanks to NewbieOrange for the pull request.
  • [#639] API: Add method CommandLine::is/setUnmatchedOptionsAllowedAsOptionParameters to disallow option parameter values resembling option names. Thanks to Peter Murray-Rust for raising this.
  • [#1074][#1075] API: Added method ParseResult::expandedArgs to return the list of arguments after @-file expansion. Thanks to Kevin Bedi for the pull request.
  • [#1052] API: Show/Hide commands in usage help on specific conditions. Thanks to Philippe Charles for raising this.
  • [#1088] API: Add method Help::allSubcommands to return all subcommands, including hidden ones. Clarify the semantics of Help::subcommands.
  • [#1090] API: Add methods Help::optionListExcludingGroups to return a String with the rendered section of the usage help containing only the specified options, including hidden ones.
  • [#1092] API: Add method Help::parameterList(List<PositionalParamSpec>) to return a String with the rendered section of the usage help containing only the specified positional parameters, including hidden ones.
  • [#1093] API: Add method Help::commandList(Map<String, Help>) to return a String with the rendered section of the usage help containing only the specified subcommands, including hidden ones.
  • [#1091] API: Add method Help::optionListGroupSections to return a String with the rendered section of the usage help containing only the option groups.
  • [#1089] API: Add method Help::createDefaultOptionSort to create a Comparator that follows the command and options' configuration.
  • [#1084][#1094] API: Add method Help::createDefaultLayout(List<OptionSpec>, List<PositionalParamSpec>, ColorScheme) to create a layout for the specified options and positionals.
  • [#1087] API: Add methods ArgumentGroupSpec::allOptionsNested and ArgumentGroupSpec::allPositionalParametersNested.
  • [#1086] API: add methods Help.Layout::addAllOptions and Help.Layout::addAllPositionals, to show all specified options, including hidden ones.
  • [#1085] API: Add method Help::optionSectionGroups to get argument groups with a header.
  • [#1101] API: Add method Help::createDetailedSynopsisOptionsText to specify which options to show in the synopsis.
  • [#1061] API: Add method Help::makeSynopsisFromParts for building complex synopsis strings; synopsis now shows non-group options before argument groups, for a more natural synopsis when groups contain only positional parameters.
  • [#983] Allow making inherited options hidden on subcommands. This can now be accomplished with the new Help methods by providing a custom option list and customizing the synopsis.
  • [#1051][#1056] Enhancement: GenerateCompletion command no longer needs to be a direct subcommand of the root command. Thanks to Philippe Charles for the pull request.
  • [#1083] Enhancement: @Command-annotated methods no longer need the enclosing class to have a @Command annotation.
  • [#1068] Enhancement: Make ParserSpec::toString output settings in alphabetic order.
  • [#1069] Enhancement: Debug output should show optionsCaseInsensitive and subcommandsCaseInsensitive settings.
  • [#1070] Enhancement: Code cleanup: removed redundant modifiers and initializations, unused variables, incorrect javadoc references, and more. Thanks to NewbieOrange for the pull request.
  • [#1096] Enhancement: Override Help.Column equals, hashCode and toString methods to facilitate testing.
  • [#1106] Enhancement: First check if JANSI is explicitly disabled without loading any JANSI classes, to avoid JANSI extracting a DLL to the temporary folder when one of its classes is loaded. This avoids problems where AppLocker can forbid loading of non-signed libraries from the Windows temporary folder. Thanks to Philippe Charles for raising this.
  • [#1110] Enhancement: Fix broken javadoc links, fix Kotlin compiler warnings, bump to latest Kotlin and Scala versions. Thanks to Andreas Deininger for the pull request.
  • [#1109][#1112] Enhancement: Fix ManPageGenerator to ensure generated AsciiDoc man pages use UTF-8 encoding. Thanks to Andreas Deininger for the pull request.
  • [#1063][#1064] ManPageGenerator now correctly excludes hidden options, parameters, and subcommands from man page generation. Thanks to Brian Demers for the pull request.
  • [#1103] Enhancement: Tests no longer fail under Cygwin/ConEmu due to ANSI in output. Thanks to David Walluck for raising this.
  • [#1055] Bugfix: The parser will no longer assign values that match an option name to options that take a parameter, unless the value is in quotes. Thanks to waacc-gh for raising this.
  • [#1015] Bugfix: Parser improvement: varargs positional arguments no longer consume unmatched options unless unmatchedOptionsArePositionalParams is configured. Thanks to Chris Smowton for raising this.
  • [#1071] Bugfix: Usage help no longer renders options header when it is specified via optionListHeading when all options are hidden.
  • [#1076] Bugfix: Don't generate Autocomplete for hidden commands. Thanks to power721 for raising this.
  • [#1081] Bugfix: CommandLine.Help constructor no longer calls overridable methods addAllSubcommands and createDefaultParamLabelRenderer.
  • [#1065] Bugfix: With a List<> option in @ArgGroup, group incorrectly appears twice in the synopsis. Thanks to kap4lin for raising this.
  • [#1067] Bugfix: ParserSpec::initFrom was not copying useSimplifiedAtFiles.
  • [#1054] Bugfix: Fixed issue in argument group parsing where incorrect input with missing mandatory elements was accepted when an option was specified multiple times. Thanks to waacc-gh for raising this.
  • [#1072] Bugfix: Mixin UsageMessageSpec::width and UsageMessageSpec::longOptionsMaxWidth is no longer ignored.
  • [#1100] Bugfix: The factory of the original CommandSpec is now correctly used in the CommandSpec copy for repeatable subcommands. Thanks to Michael Kunz for the pull request.
  • [#1058][#1059] DOC: Man page generator: fix incorrect asciidoctor call in synopsis. Thanks to Andreas Deininger for the pull request.
  • [#1058][#1060] DOC: Man page generator: add documentation about creating language variants. Thanks to Andreas Deininger for the pull request.
  • [#1120] Clean up compiler warnings.
  • [#1073] DOC: Improve user manual: fix typos, update content. Thanks to Andreas Deininger for the pull request.
  • [#1102] DOC: Show descriptionKeys for @file and EndOfOptions (--) delimiter in resource bundles.
  • [#1116] DOC: Improved Guice example in user manual. Thanks to H.Sakata for the pull request.
  • [#1098][#1117] DOC: Simplify JLine 3 documentation by moving examples for older JLine 3 and picocli to the picocli wiki. Thanks to Kevin Arthur for the pull request.
  • [#1121] DOC: Link to alternative in @deprecated Javadoc tag for Help::addSubcommand.
  • [#1099] Dependency Upgrade: Bump JLine to 3.15.0. Thanks to mattirn for the pull request.

Deprecations

No features were deprecated in this release.

Potential breaking changes

Parser Changes

The parser behaviour has changed: picocli will no longer assign values that match an option name to options that take a parameter, unless the value is in quotes.
Applications that rely on this behaviour need to use quoted values.

Error Message for Unknown Options

Unmatched arguments that look like options now result in an error message Unknown option: '-unknown'.

Previously, the error message was: Unmatched argument: '-unknown'.

Usage Help: Synopsis for Arg Groups

This release changes the synopsis for commands with argument groups:
the synopsis now shows the non-group options before argument groups, where previously argument groups were shown first.

This gives a more natural synopsis when groups contain only positional parameters.

Don't miss a new picocli release

NewReleases is sending notifications on new releases.