Picocli 4.4.0
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
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 thepositionals
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 ofHelp::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 aComparator
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
andArgumentGroupSpec::allPositionalParametersNested
. - [#1086] API: add methods
Help.Layout::addAllOptions
andHelp.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
andsubcommandsCaseInsensitive
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
andtoString
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 methodsaddAllSubcommands
andcreateDefaultParamLabelRenderer
. - [#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 copyinguseSimplifiedAtFiles
. - [#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
andUsageMessageSpec::longOptionsMaxWidth
is no longer ignored. - [#1100] Bugfix: The factory of the original
CommandSpec
is now correctly used in theCommandSpec
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 forHelp::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.