private static String concat(String infix, String... values) { return concat(infix, Arrays.asList(values)); } private static String concat(String infix, List<String> values) {
private static String concat(String infix, List<String> values) { return concat(infix, values, null, new NullFunction()); } private static <V, T extends V> String concat(String infix, List<T> values, T lastValue, Function<V, String> normalize) {
private static String optionNames(List<OptionSpec> options) { List<String> result = new ArrayList<String>(); for (OptionSpec option : options) { result.addAll(Arrays.asList(option.names())); } return concat(" ", result, "", new NullFunction()).trim(); }
private static String generateOptionsCases(List<OptionSpec> argOptionFields, String indent, String currWord) { StringBuilder buff = new StringBuilder(1024); for (OptionSpec option : argOptionFields) { if (option.completionCandidates() != null) { buff.append(format("%s %s)\n", indent, concat("|", option.names()))); // " -u|--timeUnit)\n" buff.append(format("%s COMPREPLY=( $( compgen -W \"${%s_OPTION_ARGS}\" -- %s ) )\n", indent, bashify(option.paramLabel()), currWord)); buff.append(format("%s return $?\n", indent)); buff.append(format("%s ;;\n", indent)); } else if (option.type().equals(File.class) || "java.nio.file.Path".equals(option.type().getName())) { buff.append(format("%s %s)\n", indent, concat("|", option.names()))); // " -f|--file)\n" buff.append(format("%s compopt -o filenames\n", indent)); buff.append(format("%s COMPREPLY=( $( compgen -f -- %s ) ) # files\n", indent, currWord)); buff.append(format("%s return $?\n", indent)); buff.append(format("%s ;;\n", indent)); } else if (option.type().equals(InetAddress.class)) { buff.append(format("%s %s)\n", indent, concat("|", option.names()))); // " -h|--host)\n" buff.append(format("%s compopt -o filenames\n", indent)); buff.append(format("%s COMPREPLY=( $( compgen -A hostname -- %s ) )\n", indent, currWord)); buff.append(format("%s return $?\n", indent)); buff.append(format("%s ;;\n", indent)); } else { buff.append(format("%s %s)\n", indent, concat("|", option.names()))); // no completions available buff.append(format("%s return\n", indent)); buff.append(format("%s ;;\n", indent)); } } return buff.toString(); }
private static void generateFunctionCallsToArrContains(String scriptName, List<String> predecessors, CommandLine commandLine, StringBuilder buff, List<String> functionCalls, Map<CommandDescriptor, CommandLine> function2command) { // breadth-first: generate command lists and function calls for predecessors + each subcommand for (Map.Entry<String, CommandLine> entry : commandLine.getSubcommands().entrySet()) { int count = functionCalls.size(); String functionName = "_picocli_" + scriptName + "_" + concat("_", predecessors, entry.getKey(), new Bashify()); functionCalls.add(format(" ArrContains COMP_WORDS CMDS%2$d && { %1$s; return $?; }\n", functionName, count)); buff.append( format(" CMDS%2$d=(%1$s)\n", concat(" ", predecessors, entry.getKey(), new NullFunction()), count)); // remember the function name and associated subcommand so we can easily generate a function later function2command.put(new CommandDescriptor(functionName, entry.getKey()), entry.getValue()); } // then recursively do the same for all nested subcommands for (Map.Entry<String, CommandLine> entry : commandLine.getSubcommands().entrySet()) { predecessors.add(entry.getKey()); generateFunctionCallsToArrContains(scriptName, predecessors, entry.getValue(), buff, functionCalls, function2command); predecessors.remove(predecessors.size() - 1); } } private static String concat(String infix, String... values) {
private static void generateCompletionCandidates(StringBuilder buff, OptionSpec f) { buff.append(format(" %s_OPTION_ARGS=\"%s\" # %s values\n", bashify(f.paramLabel()), concat(" ", extract(f.completionCandidates())).trim(), f.longestName())); } private static List<String> extract(Iterable<String> generator) {
List<OptionSpec> argOptionFields = filter(commandSpec.options(), negate(new BooleanArgFilter())); String argOptionNames = optionNames(argOptionFields); String commands = concat(" ", new ArrayList<String>(commandLine.getSubcommands().keySet())).trim();
private static String concat(String infix, String... values) { return concat(infix, Arrays.asList(values)); } private static String concat(String infix, List<String> values) {
private static String concat(String infix, List<String> values) { return concat(infix, values, null, new NullFunction()); } private static <V, T extends V> String concat(String infix, List<T> values, T lastValue, Function<V, String> normalize) {
private static String optionNames(List<OptionSpec> options) { List<String> result = new ArrayList<String>(); for (OptionSpec option : options) { result.addAll(Arrays.asList(option.names())); } return concat(" ", result, "", new NullFunction()).trim(); }
private static void generateFunctionCallsToArrContains(String scriptName, List<String> predecessors, CommandLine commandLine, StringBuilder buff, List<String> functionCalls, Map<CommandDescriptor, CommandLine> function2command) { // breadth-first: generate command lists and function calls for predecessors + each subcommand for (Map.Entry<String, CommandLine> entry : commandLine.getSubcommands().entrySet()) { int count = functionCalls.size(); String functionName = "_picocli_" + scriptName + "_" + concat("_", predecessors, entry.getKey(), new Bashify()); functionCalls.add(format(" ArrContains COMP_WORDS CMDS%2$d && { %1$s; return $?; }\n", functionName, count)); buff.append( format(" CMDS%2$d=(%1$s)\n", concat(" ", predecessors, entry.getKey(), new NullFunction()), count)); // remember the function name and associated subcommand so we can easily generate a function later function2command.put(new CommandDescriptor(functionName, entry.getKey()), entry.getValue()); } // then recursively do the same for all nested subcommands for (Map.Entry<String, CommandLine> entry : commandLine.getSubcommands().entrySet()) { predecessors.add(entry.getKey()); generateFunctionCallsToArrContains(scriptName, predecessors, entry.getValue(), buff, functionCalls, function2command); predecessors.remove(predecessors.size() - 1); } } private static String concat(String infix, String... values) {
private static String generateOptionsCases(List<OptionSpec> argOptionFields, String indent, String currWord) { StringBuilder buff = new StringBuilder(1024); for (OptionSpec option : argOptionFields) { if (option.completionCandidates() != null) { buff.append(format("%s %s)\n", indent, concat("|", option.names()))); // " -u|--timeUnit)\n" buff.append(format("%s COMPREPLY=( $( compgen -W \"${%s_OPTION_ARGS}\" -- %s ) )\n", indent, bashify(option.paramLabel()), currWord)); buff.append(format("%s return $?\n", indent)); buff.append(format("%s ;;\n", indent)); } else if (option.type().equals(File.class) || "java.nio.file.Path".equals(option.type().getName())) { buff.append(format("%s %s)\n", indent, concat("|", option.names()))); // " -f|--file)\n" buff.append(format("%s compopt -o filenames\n", indent)); buff.append(format("%s COMPREPLY=( $( compgen -f -- %s ) ) # files\n", indent, currWord)); buff.append(format("%s return $?\n", indent)); buff.append(format("%s ;;\n", indent)); } else if (option.type().equals(InetAddress.class)) { buff.append(format("%s %s)\n", indent, concat("|", option.names()))); // " -h|--host)\n" buff.append(format("%s compopt -o filenames\n", indent)); buff.append(format("%s COMPREPLY=( $( compgen -A hostname -- %s ) )\n", indent, currWord)); buff.append(format("%s return $?\n", indent)); buff.append(format("%s ;;\n", indent)); } else { buff.append(format("%s %s)\n", indent, concat("|", option.names()))); // no completions available buff.append(format("%s return\n", indent)); buff.append(format("%s ;;\n", indent)); } } return buff.toString(); }
private static void generateCompletionCandidates(StringBuilder buff, OptionSpec f) { buff.append(format(" %s_OPTION_ARGS=\"%s\" # %s values\n", bashify(f.paramLabel()), concat(" ", extract(f.completionCandidates())).trim(), f.longestName())); } private static List<String> extract(Iterable<String> generator) {
List<OptionSpec> argOptionFields = filter(commandSpec.options(), negate(new BooleanArgFilter())); String argOptionNames = optionNames(argOptionFields); String commands = concat(" ", new ArrayList<String>(commandLine.getSubcommands().keySet())).trim();