in log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java [3492:3569]
public String detailedSynopsis(
final int synopsisHeadingLength,
final Comparator<Field> optionSort,
final boolean clusterBooleanOptions) {
Text optionText = ansi().new Text(0);
final List<Field> fields = new ArrayList<>(optionFields); // iterate in declaration order
if (optionSort != null) {
Collections.sort(fields, optionSort); // iterate in specified sort order
}
if (clusterBooleanOptions) { // cluster all short boolean options into a single string
final List<Field> booleanOptions = new ArrayList<>();
final StringBuilder clusteredRequired = new StringBuilder("-");
final StringBuilder clusteredOptional = new StringBuilder("-");
for (final Field field : fields) {
if (field.getType() == boolean.class || field.getType() == Boolean.class) {
final Option option = field.getAnnotation(Option.class);
final String shortestName = ShortestFirst.sort(option.names())[0];
if (shortestName.length() == 2 && shortestName.startsWith("-")) {
booleanOptions.add(field);
if (option.required()) {
clusteredRequired.append(shortestName.substring(1));
} else {
clusteredOptional.append(shortestName.substring(1));
}
}
}
}
fields.removeAll(booleanOptions);
if (clusteredRequired.length() > 1) { // initial length was 1
optionText = optionText.append(" ").append(colorScheme.optionText(clusteredRequired.toString()));
}
if (clusteredOptional.length() > 1) { // initial length was 1
optionText = optionText
.append(" [")
.append(colorScheme.optionText(clusteredOptional.toString()))
.append("]");
}
}
for (final Field field : fields) {
final Option option = field.getAnnotation(Option.class);
if (!option.hidden()) {
if (option.required()) {
optionText =
appendOptionSynopsis(optionText, field, ShortestFirst.sort(option.names())[0], " ", "");
if (isMultiValue(field)) {
optionText = appendOptionSynopsis(
optionText, field, ShortestFirst.sort(option.names())[0], " [", "]...");
}
} else {
optionText = appendOptionSynopsis(
optionText, field, ShortestFirst.sort(option.names())[0], " [", "]");
if (isMultiValue(field)) {
optionText = optionText.append("...");
}
}
}
}
for (final Field positionalParam : positionalParametersFields) {
if (!positionalParam.getAnnotation(Parameters.class).hidden()) {
optionText = optionText.append(" ");
final Text label = parameterLabelRenderer.renderParameterLabel(
positionalParam, colorScheme.ansi(), colorScheme.parameterStyles);
optionText = optionText.append(label);
}
}
// Fix for #142: first line of synopsis overshoots max. characters
final int firstColumnLength = commandName.length() + synopsisHeadingLength;
// synopsis heading ("Usage: ") may be on the same line, so adjust column width
final TextTable textTable = new TextTable(ansi(), firstColumnLength, usageHelpWidth - firstColumnLength);
textTable.indentWrappedLines =
1; // don't worry about first line: options (2nd column) always start with a space
// right-adjust the command name by length of synopsis heading
final Text PADDING = Ansi.OFF.new Text(stringOf('X', synopsisHeadingLength));
textTable.addRowValues(PADDING.append(colorScheme.commandText(commandName)), optionText);
return textTable.toString().substring(synopsisHeadingLength); // cut off leading synopsis heading spaces
}