From 93bba037291b064d0c2a0b90c66c272f4631abb4 Mon Sep 17 00:00:00 2001 From: Toshiaki Maki Date: Fri, 29 Jan 2021 00:14:56 +0900 Subject: [PATCH] Add cli-completion mode in --help gh-53 --- src/main/java/am/ik/rsocket/Args.java | 17 ++++- .../rsocket/CliCompletionHelpFormatter.java | 65 +++++++++++++++++++ .../am/ik/rsocket/RscCommandLineRunner.java | 7 +- .../am/ik/rsocket/RscApplicationTests.java | 7 +- 4 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 src/main/java/am/ik/rsocket/CliCompletionHelpFormatter.java diff --git a/src/main/java/am/ik/rsocket/Args.java b/src/main/java/am/ik/rsocket/Args.java index d501c4b..746e88f 100644 --- a/src/main/java/am/ik/rsocket/Args.java +++ b/src/main/java/am/ik/rsocket/Args.java @@ -49,6 +49,7 @@ import io.rsocket.metadata.WellKnownMimeType; import io.rsocket.transport.ClientTransport; import io.rsocket.util.DefaultPayload; +import joptsimple.HelpFormatter; import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; @@ -66,7 +67,7 @@ public class Args { private final OptionSpec version = parser.acceptsAll(Arrays.asList("v", "version"), "Print version"); - private final OptionSpec help = parser.acceptsAll(Arrays.asList("help"), "Print help"); + private final OptionSpec help = parser.acceptsAll(Arrays.asList("h", "help"), "Print help").withOptionalArg(); private final OptionSpec wiretap = parser.acceptsAll(Arrays.asList("w", "wiretap"), "Enable wiretap"); @@ -606,6 +607,10 @@ public boolean help() { return this.options.has(this.help); } + public String helpFormatter() { + return this.options.valueOf(this.help); + } + public boolean version() { return this.options.has(this.version); } @@ -621,6 +626,16 @@ public void printHelp(PrintStream stream) { } } + public void printHelp(PrintStream stream, HelpFormatter helpFormatter) { + try { + this.parser.formatHelpWith(helpFormatter); + this.parser.printHelpOn(stream); + } + catch (IOException e) { + throw new UncheckedIOException(e); + } + } + public boolean showSystemProperties() { return this.options.has(this.showSystemProperties); } diff --git a/src/main/java/am/ik/rsocket/CliCompletionHelpFormatter.java b/src/main/java/am/ik/rsocket/CliCompletionHelpFormatter.java new file mode 100644 index 0000000..821c36b --- /dev/null +++ b/src/main/java/am/ik/rsocket/CliCompletionHelpFormatter.java @@ -0,0 +1,65 @@ +package am.ik.rsocket; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import io.rsocket.metadata.TracingMetadataCodec; +import joptsimple.HelpFormatter; +import joptsimple.OptionDescriptor; + +public class CliCompletionHelpFormatter implements HelpFormatter { + private final Map possibleValues = new HashMap() { + { + put("am.ik.rsocket.InteractionModel", InteractionModel.values()); + put("io.rsocket.metadata.TracingMetadataCodec$Flags", TracingMetadataCodec.Flags.values()); + } + }; + + @Override + public String format(Map options) { + Comparator comparator = Comparator.comparing(optionDescriptor -> optionDescriptor.options().iterator().next()); + Set sorted = new TreeSet<>(comparator); + sorted.addAll(options.values()); + final StringBuilder sb = new StringBuilder(); + sb.append("name: rsc").append(System.lineSeparator()); + sb.append("binary_name: rsc").append(System.lineSeparator()); + sb.append("before_help: |").append(System.lineSeparator()); + sb.append(" usage: rsc Uri [Options]").append(System.lineSeparator()); + sb.append(" Non-option arguments: [String: Uri]").append(System.lineSeparator()); + sb.append(System.lineSeparator()); + sb.append("args:").append(System.lineSeparator()); + sorted.forEach(descriptor -> { + final List opts = new ArrayList<>(descriptor.options()); + if (opts.contains("[arguments]")) { + return; + } + Collections.sort(opts, Comparator.comparingInt(String::length).reversed()); + final String longest = opts.get(0); + final String shortest = opts.get(opts.size() - 1); + sb.append("- ").append(longest).append(":").append(System.lineSeparator()); + if (shortest.length() == 1) { + sb.append(" short: ").append(shortest).append(System.lineSeparator()); + opts.remove(shortest); + } + sb.append(" long: ").append(longest).append(System.lineSeparator()); + if (opts.size() > 1) { + sb.append(" aliases: ").append(opts.subList(1, opts.size())).append(System.lineSeparator()); + } + sb.append(" required: ").append(descriptor.isRequired()).append(System.lineSeparator()); + sb.append(" about: \"").append(descriptor.description()).append("\"").append(System.lineSeparator()); + final String indicator = descriptor.argumentTypeIndicator(); + sb.append(" takes_value: ").append(!"".equals(indicator)).append(System.lineSeparator()); + if (possibleValues.containsKey(indicator)) { + sb.append(" possible_values: ").append(Arrays.toString(possibleValues.get(indicator))).append(System.lineSeparator()); + } + }); + return sb.toString(); + } +} diff --git a/src/main/java/am/ik/rsocket/RscCommandLineRunner.java b/src/main/java/am/ik/rsocket/RscCommandLineRunner.java index d867797..7870500 100644 --- a/src/main/java/am/ik/rsocket/RscCommandLineRunner.java +++ b/src/main/java/am/ik/rsocket/RscCommandLineRunner.java @@ -42,7 +42,12 @@ public void run(String... a) throws Exception { final Args args = new Args(a); try { if (args.help()) { - args.printHelp(System.out); + if ("cli-completion".equals(args.helpFormatter())) { + args.printHelp(System.out, new CliCompletionHelpFormatter()); + } + else { + args.printHelp(System.out); + } return; } if (args.version()) { diff --git a/src/test/java/am/ik/rsocket/RscApplicationTests.java b/src/test/java/am/ik/rsocket/RscApplicationTests.java index 2173464..25119b8 100644 --- a/src/test/java/am/ik/rsocket/RscApplicationTests.java +++ b/src/test/java/am/ik/rsocket/RscApplicationTests.java @@ -12,9 +12,14 @@ class RscApplicationTests { @Test - void test(CapturedOutput capture) throws Exception { + void help(CapturedOutput capture) throws Exception { RscApplication.main(new String[] { "-h" }); assertThat(capture.toString()).isNotEmpty(); } + @Test + void helpYamlMode(CapturedOutput capture) throws Exception { + RscApplication.main(new String[] { "-h", "cli-completion" }); + assertThat(capture.toString()).isNotEmpty(); + } }