Skip to content

Commit f5de8e3

Browse files
author
serg-v
committed
picocli fish completion
1 parent 9c4e8a2 commit f5de8e3

File tree

2 files changed

+93
-33
lines changed

2 files changed

+93
-33
lines changed

src/main/java/picocli/AutoComplete.java

Lines changed: 93 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -305,17 +305,6 @@ private static class CommandDescriptor {
305305
this.commandName = commandName;
306306
this.commandLine = commandLine;
307307
}
308-
309-
@Override
310-
public String toString() {
311-
return "CommandDescriptor{" +
312-
"functionName='" + functionName + '\'' +
313-
", parentFunctionName='" + parentFunctionName + '\'' +
314-
", parentWithoutTopLevelCommand='" + parentWithoutTopLevelCommand + '\'' +
315-
", commandName='" + commandName + '\'' +
316-
", commandLine=" + commandLine +
317-
'}';
318-
}
319308
}
320309

321310
private static final String SCRIPT_HEADER = "" +
@@ -551,18 +540,105 @@ public static String fish(String scriptName, CommandLine commandLine) {
551540
if (commandLine == null) { throw new NullPointerException("commandLine"); }
552541
List<CommandDescriptor> hierarchy = createHierarchy(scriptName, commandLine);
553542
//print hierarchy
543+
StringBuilder result = new StringBuilder();
544+
//result.append("complete --command ").append(scriptName).append(" --no-files").append("\n");
545+
546+
String parentFunction = "";
547+
List<CommandDescriptor> currentLevel = new ArrayList<>();
548+
List<String> currentLevelCommands = new ArrayList<>();
549+
550+
CommandDescriptor rootDescriptor = null;
554551
for (CommandDescriptor descriptor : hierarchy) {
555-
System.out.println(descriptor.functionName + " " + descriptor.commandName);
556-
}
552+
if (descriptor.parentFunctionName.equals("")) {
553+
rootDescriptor = descriptor;
554+
continue;
555+
}
556+
if (!descriptor.parentFunctionName.equals(parentFunction)) {
557+
if (!currentLevelCommands.isEmpty()) {
558+
processLevel(scriptName, result, currentLevel, currentLevelCommands, parentFunction, rootDescriptor);
559+
rootDescriptor = null;
557560

558-
StringBuilder result = new StringBuilder();
559-
result.append("Hello from fish!").append("\n");
560-
for (CommandDescriptor commandDescriptor : hierarchy) {
561-
result.append(commandDescriptor.toString()).append("\n");
561+
currentLevel.clear();
562+
currentLevelCommands.clear();
563+
}
564+
parentFunction = descriptor.parentFunctionName;
565+
}
566+
567+
currentLevel.add(descriptor);
568+
currentLevelCommands.add(descriptor.commandName);
562569
}
570+
if (!currentLevelCommands.isEmpty()) {
571+
processLevel(scriptName, result, currentLevel, currentLevelCommands, parentFunction, rootDescriptor);
572+
}
573+
574+
563575
return result.toString();
564576
}
565577

578+
private static void processLevel(String scriptName, StringBuilder result, List<CommandDescriptor> currentLevel,
579+
List<String> currentLevelCommands, String levelName,
580+
CommandDescriptor rootDescriptor) {
581+
result.append("\n# ").append(levelName).append(" completion \n");
582+
result.append("set -l ").append(levelName).append(" ").append(String.join(" ", currentLevelCommands)).append(
583+
"\n");
584+
if (rootDescriptor != null) {
585+
for (OptionSpec optionSpec : rootDescriptor.commandLine.getCommandSpec().options()) {
586+
result.append("complete -c ").append(scriptName);
587+
result.append(" -n \"not __fish_seen_subcommand_from $").append(levelName).append("\"");
588+
result.append(" -l ").append(optionSpec.longestName().replace("--", ""));
589+
String optionDescription = sanitizeDescription(optionSpec.description().length > 0 ? optionSpec.description()[0] : "");
590+
result.append(" -d '").append(optionDescription).append("'\n");
591+
592+
if (!optionSpec.shortestName().equals(optionSpec.longestName())) {
593+
result.append("complete -c ").append(scriptName);
594+
result.append(" -n \"not __fish_seen_subcommand_from $").append(levelName).append("\"");
595+
result.append(" -s ").append(optionSpec.shortestName().replace("-", ""));
596+
result.append(" -d '").append(optionDescription).append("'\n");
597+
}
598+
}
599+
}
600+
for (CommandDescriptor commandDescriptor : currentLevel) {
601+
String[] descriptions = commandDescriptor.commandLine.getCommandSpec().usageMessage().description();
602+
String description = descriptions.length > 0 ? descriptions[0] : "";
603+
result.append("complete -c ").append(scriptName);
604+
result.append(" -f"); // do not show files
605+
result.append(" -n \"not __fish_seen_subcommand_from $").append(levelName).append("\"");
606+
if (!commandDescriptor.parentWithoutTopLevelCommand.equals("")) {
607+
result.append(" -n '__fish_seen_subcommand_from ").append(
608+
commandDescriptor.parentWithoutTopLevelCommand).append("'");
609+
}
610+
result.append(" -a ").append(commandDescriptor.commandName).append(" -d '").append(description).append("'\n");
611+
612+
for (OptionSpec optionSpec : commandDescriptor.commandLine.getCommandSpec().options()) {
613+
result.append("complete -c ").append(scriptName);
614+
result.append(" -n \"__fish_seen_subcommand_from ").append(commandDescriptor.commandName).append("\"");
615+
if (!commandDescriptor.parentWithoutTopLevelCommand.equals("")) {
616+
result.append(" -n '__fish_seen_subcommand_from ").append(
617+
commandDescriptor.parentWithoutTopLevelCommand).append("'");
618+
}
619+
result.append(" -l ").append(optionSpec.longestName().replace("--", ""));
620+
String optionDescription = sanitizeDescription(optionSpec.description().length > 0 ? optionSpec.description()[0] : "");
621+
result.append(" -d '").append(optionDescription).append("'\n");
622+
623+
if (!optionSpec.shortestName().equals(optionSpec.longestName())) {
624+
result.append("complete -c ").append(scriptName);
625+
result.append(" -n \"__fish_seen_subcommand_from ").append(commandDescriptor.commandName).append("\"");
626+
if (!commandDescriptor.parentWithoutTopLevelCommand.equals("")) {
627+
result.append(" -n '__fish_seen_subcommand_from ").append(
628+
commandDescriptor.parentWithoutTopLevelCommand).append("'");
629+
}
630+
result.append(" -s ").append(optionSpec.shortestName().replace("-", ""));
631+
result.append(" -d '").append(optionDescription).append("'\n");
632+
}
633+
}
634+
}
635+
636+
}
637+
638+
private static String sanitizeDescription(String description) {
639+
return description.replace("'", "\\'");
640+
}
641+
566642
private static List<CommandDescriptor> createHierarchy(String scriptName, CommandLine commandLine) {
567643
List<CommandDescriptor> result = new ArrayList<CommandDescriptor>();
568644
result.add(new CommandDescriptor("_picocli_" + scriptName, "", "", scriptName, commandLine));

src/test/java/picocli/AutoCompleteTest.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2117,20 +2117,4 @@ public void testIssue1388_AliasesCommand() throws FileNotFoundException {
21172117
existingScript.delete();
21182118
}
21192119
}
2120-
2121-
@Test
2122-
public void testFish() {
2123-
String expected = String.format("hello from fish%n");
2124-
2125-
assertEquals(
2126-
expected,
2127-
AutoComplete.fish("myapp", new CommandLine(new Issue1352CommandWithResourceBundle()))
2128-
);
2129-
2130-
assertEquals(
2131-
expected,
2132-
AutoComplete.fish("myapp", new CommandLine(new Issue1352ParentCommand()))
2133-
);
2134-
2135-
}
21362120
}

0 commit comments

Comments
 (0)