我如何构建帮助功能以将子命令分成具有单独描述性 headers 的组?
How can I construct the help functionality to divide subcommands into groups with separate descriptive headers?
我目前正在使用的一个工具有很多子命令,这使得 picocli 的帮助输出不清楚。我的代码如下所示:
@Command(name = "toolName",
version = "version",
sortOptions = false,
parameterListHeading = "%nParameters:%n",
optionListHeading = "%nOptions:%n",
commandListHeading = "%nThese are common commands:%n%n",
subcommands = {
command1.class,
command2.class,
command3.class,
etc.class }
帮助如下:
@Option(names = {"-h", "--help"}, scope = ScopeType.INHERIT, usageHelp = true,
description = "Display this help message.")
boolean usageHelpRequested;
我希望帮助输出看起来类似于 git 的:
git bash --help output
这里的子命令被分成不同的功能(比如启动一个工作区)并带有描述。这可能使用 picocli 吗?
是的,通过深入了解 picocli 的帮助 API。
一个想法是自定义 IHelpSectionRenderer
,请参阅此示例:https://github.com/remkop/picocli/blob/main/picocli-examples/src/main/java/picocli/examples/customhelp/GroupingDemo.java
我按照建议定制了一个 IHelpSectionRenderer。如果有人感兴趣:
@Command(name = "help", helpCommand = true)
class Help implements Runnable {
public static Map<String, String[]> commandGroups;
static {
commandGroups = new HashMap<>();
commandGroups.put("group1", new String[]{
"function1", "function2", "function3"});
commandGroups.put("group2", new String[]{
"function3", "function4", "function5"});
}
@Override
public void run() {
CommandLine cmd = new CommandLine(new Tool());
cmd.getHelpSectionMap().remove(SECTION_KEY_COMMAND_LIST_HEADING);
cmd.getHelpSectionMap().remove(SECTION_KEY_COMMAND_LIST);
List<String> keys = new ArrayList<>(cmd.getHelpSectionKeys());
for (String group : commandGroups.keySet()) {
String headerSection = "SECTION_KEY_" + group + "_HEADING";
String commandSection = "SECTION_KEY_" + group;
cmd.getHelpSectionMap().put(headerSection,
help -> help.createHeading("%n" + group + ":%n"));
cmd.getHelpSectionMap().put(commandSection,
new CommandListRenderer(commandGroups.get(group)));
keys.add(headerSection);
keys.add(commandSection);
}
cmd.setHelpSectionKeys(keys);
cmd.usage(System.out);
}
}
class CommandListRenderer implements IHelpSectionRenderer {
String[] functions;
public CommandListRenderer(String[] f) {
functions = f;
}
//@Override
public String render(Help help) {
CommandSpec spec = help.commandSpec();
if (spec.subcommands().isEmpty()) { return ""; }
// prepare layout: two columns
// the left column overflows, the right column wraps if text is too long
Help.TextTable textTable =
Help.TextTable.forColumns(help.colorScheme(),
new Help.Column(30, 2, Help.Column.Overflow.SPAN),
new Help.Column(spec.usageMessage().width() - 30, 2,
Help.Column.Overflow.TRUNCATE));
for (String f : functions) {
CommandLine subcommand = spec.subcommands().get(f);
if (subcommand == null) {
throw new NotFoundException("Function not found: " + f);
}
addCommand(subcommand, textTable);
}
return textTable.toString();
}
public void addCommand(CommandLine cmd, Help.TextTable textTable) {
// create comma-separated list of command name and aliases
String names = cmd.getCommandSpec().names().toString();
names = names.substring(1, names.length() - 1); // remove leading '[' and trailing ']'
// command description is taken from header or description
String description = description(cmd.getCommandSpec().usageMessage());
// add a line for this command to the layout
textTable.addRowValues(names, description);
}
private String description(Model.UsageMessageSpec usageMessage) {
if (usageMessage.header().length > 0) {
return usageMessage.header()[0];
}
if (usageMessage.description().length > 0) {
return usageMessage.description()[0];
}
return "";
}
}
我目前正在使用的一个工具有很多子命令,这使得 picocli 的帮助输出不清楚。我的代码如下所示:
@Command(name = "toolName",
version = "version",
sortOptions = false,
parameterListHeading = "%nParameters:%n",
optionListHeading = "%nOptions:%n",
commandListHeading = "%nThese are common commands:%n%n",
subcommands = {
command1.class,
command2.class,
command3.class,
etc.class }
帮助如下:
@Option(names = {"-h", "--help"}, scope = ScopeType.INHERIT, usageHelp = true,
description = "Display this help message.")
boolean usageHelpRequested;
我希望帮助输出看起来类似于 git 的:
git bash --help output
这里的子命令被分成不同的功能(比如启动一个工作区)并带有描述。这可能使用 picocli 吗?
是的,通过深入了解 picocli 的帮助 API。
一个想法是自定义 IHelpSectionRenderer
,请参阅此示例:https://github.com/remkop/picocli/blob/main/picocli-examples/src/main/java/picocli/examples/customhelp/GroupingDemo.java
我按照建议定制了一个 IHelpSectionRenderer。如果有人感兴趣:
@Command(name = "help", helpCommand = true)
class Help implements Runnable {
public static Map<String, String[]> commandGroups;
static {
commandGroups = new HashMap<>();
commandGroups.put("group1", new String[]{
"function1", "function2", "function3"});
commandGroups.put("group2", new String[]{
"function3", "function4", "function5"});
}
@Override
public void run() {
CommandLine cmd = new CommandLine(new Tool());
cmd.getHelpSectionMap().remove(SECTION_KEY_COMMAND_LIST_HEADING);
cmd.getHelpSectionMap().remove(SECTION_KEY_COMMAND_LIST);
List<String> keys = new ArrayList<>(cmd.getHelpSectionKeys());
for (String group : commandGroups.keySet()) {
String headerSection = "SECTION_KEY_" + group + "_HEADING";
String commandSection = "SECTION_KEY_" + group;
cmd.getHelpSectionMap().put(headerSection,
help -> help.createHeading("%n" + group + ":%n"));
cmd.getHelpSectionMap().put(commandSection,
new CommandListRenderer(commandGroups.get(group)));
keys.add(headerSection);
keys.add(commandSection);
}
cmd.setHelpSectionKeys(keys);
cmd.usage(System.out);
}
}
class CommandListRenderer implements IHelpSectionRenderer {
String[] functions;
public CommandListRenderer(String[] f) {
functions = f;
}
//@Override
public String render(Help help) {
CommandSpec spec = help.commandSpec();
if (spec.subcommands().isEmpty()) { return ""; }
// prepare layout: two columns
// the left column overflows, the right column wraps if text is too long
Help.TextTable textTable =
Help.TextTable.forColumns(help.colorScheme(),
new Help.Column(30, 2, Help.Column.Overflow.SPAN),
new Help.Column(spec.usageMessage().width() - 30, 2,
Help.Column.Overflow.TRUNCATE));
for (String f : functions) {
CommandLine subcommand = spec.subcommands().get(f);
if (subcommand == null) {
throw new NotFoundException("Function not found: " + f);
}
addCommand(subcommand, textTable);
}
return textTable.toString();
}
public void addCommand(CommandLine cmd, Help.TextTable textTable) {
// create comma-separated list of command name and aliases
String names = cmd.getCommandSpec().names().toString();
names = names.substring(1, names.length() - 1); // remove leading '[' and trailing ']'
// command description is taken from header or description
String description = description(cmd.getCommandSpec().usageMessage());
// add a line for this command to the layout
textTable.addRowValues(names, description);
}
private String description(Model.UsageMessageSpec usageMessage) {
if (usageMessage.header().length > 0) {
return usageMessage.header()[0];
}
if (usageMessage.description().length > 0) {
return usageMessage.description()[0];
}
return "";
}
}