diff --git a/.github/workflows/dejagnu.yml b/.github/workflows/dejagnu.yml new file mode 100644 index 000000000..d71fafef9 --- /dev/null +++ b/.github/workflows/dejagnu.yml @@ -0,0 +1,27 @@ +name: DejaGnu Tests + +on: [ push, pull_request ] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Install Fish shell and DejaGnu + run: | + sudo apt-add-repository -y ppa:fish-shell/release-3 + sudo apt-get update + sudo apt-get install -y fish dejagnu tcllib + - name: Check versions + run: | + fish --version + runtest --version + - name: Checkout + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v2 + - name: Run DejaGnu fish tests + run: | + cd src/test/dejagnu.fishtests + ./runCompletion + - name: Run DejaGnu bash tests + run: | + cd src/test/dejagnu.tests + ./runCompletion diff --git a/.gitignore b/.gitignore index 5f9ca8177..a7537ce7f 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,7 @@ picocli.iml /src/test/dejagnu.tests/testrun.log /src/test/dejagnu.tests/testrun.sum /src/test/dejagnu.tests/tmp/ +/src/test/dejagnu.fishtests/log/completion.sum +/src/test/dejagnu.fishtests/log/completion.log /picocli-tests-java567/gradle/wrapper/dists/**/*.lck /picocli-tests-java567/gradle/wrapper/dists/**/*.ok diff --git a/docs/man/index.html b/docs/man/index.html index 6442f11de..08f67de29 100644 --- a/docs/man/index.html +++ b/docs/man/index.html @@ -435,81 +435,81 @@ #footer-text{color:rgba(0,0,0,.6);font-size:.9em}} @media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}} - - - + + + diff --git a/docs/zh/picocli-2.0-do-more-with-less.html b/docs/zh/picocli-2.0-do-more-with-less.html index ed5d027fd..bc4735113 100644 --- a/docs/zh/picocli-2.0-do-more-with-less.html +++ b/docs/zh/picocli-2.0-do-more-with-less.html @@ -525,81 +525,81 @@ .CodeRay .change .change{color:#66f} .CodeRay .head .head{color:#f4f} - - - + + + diff --git a/docs/zh/picocli-2.0-groovy-scripts-on-steroids.html b/docs/zh/picocli-2.0-groovy-scripts-on-steroids.html index 03efa574f..d0170a7df 100644 --- a/docs/zh/picocli-2.0-groovy-scripts-on-steroids.html +++ b/docs/zh/picocli-2.0-groovy-scripts-on-steroids.html @@ -525,81 +525,81 @@ .CodeRay .change .change{color:#66f} .CodeRay .head .head{color:#f4f} - - - + + + diff --git a/src/main/java/picocli/AutoComplete.java b/src/main/java/picocli/AutoComplete.java index 17e9580d1..16bf3fa13 100644 --- a/src/main/java/picocli/AutoComplete.java +++ b/src/main/java/picocli/AutoComplete.java @@ -534,6 +534,129 @@ public static String bash(String scriptName, CommandLine commandLine) { return result.toString(); } + + public static String fish(String scriptName, CommandLine commandLine) { + if (scriptName == null) { throw new NullPointerException("scriptName"); } + if (commandLine == null) { throw new NullPointerException("commandLine"); } + List hierarchy = createHierarchy(scriptName, commandLine); + StringBuilder result = new StringBuilder(); + + String parentFunction = ""; + List currentLevel = new ArrayList(); + List currentLevelCommands = new ArrayList(); + + CommandDescriptor rootDescriptor = null; + for (CommandDescriptor descriptor : hierarchy) { + if (descriptor.parentFunctionName.equals("")) { + rootDescriptor = descriptor; + parentFunction = descriptor.functionName; + continue; + } + if (!descriptor.parentFunctionName.equals(parentFunction)) { + processLevel(scriptName, result, currentLevel, currentLevelCommands, parentFunction, rootDescriptor); + rootDescriptor = null; + + currentLevel.clear(); + currentLevelCommands.clear(); + parentFunction = descriptor.parentFunctionName; + } + + currentLevel.add(descriptor); + currentLevelCommands.add(descriptor.commandName); + } + processLevel(scriptName, result, currentLevel, currentLevelCommands, parentFunction, rootDescriptor); + + + return result.toString(); + } + + private static void processLevel(String scriptName, StringBuilder result, List currentLevel, + List currentLevelCommands, String levelName, + CommandDescriptor rootDescriptor) { + if (levelName.equals("")) { + levelName = "root"; + } + + // fish doesn't like dashes in variable names + levelName = levelName.replaceAll("-", "_"); + + result.append("\n# ").append(levelName).append(" completion\n"); + result.append("set -l ").append(levelName); + if (!currentLevelCommands.isEmpty()) { + result.append(" ").append(join(" ", currentLevelCommands)); + } + result.append("\n"); + if (rootDescriptor != null) { + String condition = " --condition \"not __fish_seen_subcommand_from $" + levelName + "\""; + for (OptionSpec optionSpec : rootDescriptor.commandLine.getCommandSpec().options()) { + completeFishOption(scriptName, optionSpec, condition, result); + } + } + for (CommandDescriptor commandDescriptor : currentLevel) { + + result.append("complete -c ").append(scriptName); + result.append(" --no-files"); // do not show files + result.append(" --condition \"not __fish_seen_subcommand_from $").append(levelName).append("\""); + if (!commandDescriptor.parentWithoutTopLevelCommand.equals("")) { + result.append(" --condition '__fish_seen_subcommand_from ").append( + commandDescriptor.parentWithoutTopLevelCommand).append("'"); + } + + result.append(" --arguments ").append(commandDescriptor.commandName); + + String[] descriptions = commandDescriptor.commandLine.getCommandSpec().usageMessage().description(); + String description = descriptions.length > 0 ? descriptions[0] : ""; + result.append(" -d '").append(sanitizeFishDescription(description)).append("'\n"); + + String condition = getFishCondition(commandDescriptor); + for (OptionSpec optionSpec : commandDescriptor.commandLine.getCommandSpec().options()) { + completeFishOption(scriptName, optionSpec, condition, result); + } + } + } + + private static String getFishCondition(CommandDescriptor commandDescriptor) { + StringBuilder condition = new StringBuilder(); + condition.append(" --condition \"__fish_seen_subcommand_from ").append(commandDescriptor.commandName).append("\""); + if (!commandDescriptor.parentWithoutTopLevelCommand.equals("")) { + condition.append(" --condition '__fish_seen_subcommand_from ").append( + commandDescriptor.parentWithoutTopLevelCommand).append("'"); + } + return condition.toString(); + } + + private static void completeFishOption(String scriptName, OptionSpec optionSpec, String conditions, StringBuilder result) { + result.append("complete -c ").append(scriptName); + result.append(conditions); + result.append(" --long-option ").append(optionSpec.longestName().replace("--", "")); + + if (!optionSpec.shortestName().equals(optionSpec.longestName())) { + result.append(" --short-option ").append(optionSpec.shortestName().replace("-", "")); + } + + if (optionSpec.completionCandidates() != null) { + result.append(" --no-files --arguments '").append(join(" ", extract(optionSpec.completionCandidates()))).append("' "); + } + + String optionDescription = sanitizeFishDescription(optionSpec.description().length > 0 ? optionSpec.description()[0] : ""); + result.append(" -d '").append(optionDescription).append("'\n"); + } + + private static String sanitizeFishDescription(String description) { + return description.replace("'", "\\'"); + } + + private static String join(String delimeter, List list) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < list.size(); i++) { + if (i > 0) { + result.append(delimeter); + } + result.append(list.get(i)); + } + return result.toString(); + } + private static List createHierarchy(String scriptName, CommandLine commandLine) { List result = new ArrayList(); result.add(new CommandDescriptor("_picocli_" + scriptName, "", "", scriptName, commandLine)); diff --git a/src/test/dejagnu.fishtests/README.adoc b/src/test/dejagnu.fishtests/README.adoc new file mode 100644 index 000000000..28caddea8 --- /dev/null +++ b/src/test/dejagnu.fishtests/README.adoc @@ -0,0 +1,4 @@ +Run +``` +runtest --outdir log --tool completion +``` \ No newline at end of file diff --git a/src/test/dejagnu.fishtests/completion/basicExample.exp b/src/test/dejagnu.fishtests/completion/basicExample.exp new file mode 100644 index 000000000..87b8ad714 --- /dev/null +++ b/src/test/dejagnu.fishtests/completion/basicExample.exp @@ -0,0 +1,23 @@ +set timeout 1 + +# Setup completion and fake command +send "source ../resources/basic.fish\r" +expect -re "(.+>)" + +send "function basicExample; echo 'do'; end\r" +expect -re "(.+>)" + +set cmd "basicExample -" +set test "Tab should show options for '$cmd'" +set candidates "-t -u --timeout --timeUnit --timeUnit=" +run_completion_test $cmd $test $candidates + +set cmd "basicExample --" +set test "Tab should show options for '$cmd'" +set candidates "--timeout --timeUnit --timeUnit=" +run_completion_test $cmd $test $candidates + +set cmd "basicExample --timeUnit=" +set test "Tab should show time unit enum values for '$cmd'" +set candidates ".*timeUnit=DAYS.*timeUnit=MICROSECONDS.*timeUnit=MINUTES.*timeUnit=SECONDS.*timeUnit=HOURS.*timeUnit=MILLISECONDS.*timeUnit=NANOSECONDS.*" +run_completion_test $cmd $test $candidates diff --git a/src/test/dejagnu.fishtests/completion/picocompletion-demo.exp b/src/test/dejagnu.fishtests/completion/picocompletion-demo.exp new file mode 100644 index 000000000..b7fe60c88 --- /dev/null +++ b/src/test/dejagnu.fishtests/completion/picocompletion-demo.exp @@ -0,0 +1,24 @@ +exp_internal 1 +set timeout 1 + +# Setup completion and fake command +send "source ../resources/picocompletion-demo_completion.fish\r" +expect -re "(.+>)" + +send "function picocompletion-demo; echo 'do'; end\r" +expect -re "(.+>)" + +set cmd "picocompletion-demo " +set test "Tab should show sub1 and sub2 for '${cmd}'" +# for some reason, bash completion doesn't show sub1-alias and sub2-alias +set candidates "sub1.*sub1-alias.*sub2.*sub2-alias.*" +run_completion_test $cmd $test $candidates + +# now we show files in this test +# set cmd "picocompletion-demo sub1 " +# set test "Tab should not show completions for '${cmd}'" + +set cmd "picocompletion-demo sub1 -" +set test "Tab should show sub1 options for '${cmd}'" +set candidates "--candidates.*--candidates=.*--num.*--str.*" +run_completion_test $cmd $test $candidates diff --git a/src/test/dejagnu.fishtests/lib/completion.exp b/src/test/dejagnu.fishtests/lib/completion.exp new file mode 100644 index 000000000..073f24663 --- /dev/null +++ b/src/test/dejagnu.fishtests/lib/completion.exp @@ -0,0 +1,8 @@ +exp_spawn fish --no-config +expect -re "(.+>)" + +# Set terminal size to my notebook's resolution +send "stty rows 53 cols 190\r" +expect -re "(.+>)" + +source $::srcdir/lib/library.exp diff --git a/src/test/dejagnu.fishtests/lib/library.exp b/src/test/dejagnu.fishtests/lib/library.exp new file mode 100644 index 000000000..e2fb3f33f --- /dev/null +++ b/src/test/dejagnu.fishtests/lib/library.exp @@ -0,0 +1,11 @@ +proc run_completion_test {cmd test candidates} { + exp_internal 1 + send "${cmd}\t" + expect { + -re "(\n${candidates}\u001b)" { pass $test } + timeout { fail $test } + } + exp_internal 0 + send "\x03" + expect ">" +} diff --git a/src/test/dejagnu.fishtests/runCompletion b/src/test/dejagnu.fishtests/runCompletion new file mode 100755 index 000000000..a475f1f18 --- /dev/null +++ b/src/test/dejagnu.fishtests/runCompletion @@ -0,0 +1,3 @@ +#!/bin/bash +mkdir -p log +runtest --outdir log --tool completion diff --git a/src/test/dejagnu.tests/runCompletion b/src/test/dejagnu.tests/runCompletion old mode 100644 new mode 100755 diff --git a/src/test/java/picocli/AutoCompleteDejaGnuTest.java b/src/test/java/picocli/AutoCompleteDejaGnuTest.java index 0c2363c98..280baeb50 100644 --- a/src/test/java/picocli/AutoCompleteDejaGnuTest.java +++ b/src/test/java/picocli/AutoCompleteDejaGnuTest.java @@ -67,11 +67,19 @@ public void tryRunDejaGnuCompletionTests() throws Exception { // ignores test if dejagnu not installed org.junit.Assume.assumeTrue("dejagnu must be installed to run this test", isDejaGnuInstalled()); - runDejaGnuCompletionTests(); + runDejaGnuCompletionTests("src/test/dejagnu.tests"); } - private void runDejaGnuCompletionTests() throws Exception { - final File testDir = new File("src/test/dejagnu.tests"); + @Test + public void tryRunFishDejaGnuCompletionTests() throws Exception { + // ignores test if dejagnu not installed + org.junit.Assume.assumeTrue("dejagnu must be installed to run this test", isDejaGnuInstalled()); + runDejaGnuCompletionTests("src/test/dejagnu.fishtests"); + } + + + private void runDejaGnuCompletionTests(String pathname) throws Exception { + final File testDir = new File(pathname); assertTrue(testDir.getAbsolutePath() + " should exist", testDir.exists()); File runCompletionScript = new File(testDir, "runCompletion"); assertTrue(runCompletionScript.getAbsolutePath() + " should exist", runCompletionScript.exists()); diff --git a/src/test/java/picocli/AutoCompleteTest.java b/src/test/java/picocli/AutoCompleteTest.java index 0397eaf7a..4f5bb39a3 100644 --- a/src/test/java/picocli/AutoCompleteTest.java +++ b/src/test/java/picocli/AutoCompleteTest.java @@ -91,6 +91,14 @@ public void basic() throws Exception { assertEquals(expected, script); } + @Test + public void basicFish() throws Exception { + String script = AutoComplete.fish("basicExample", new CommandLine(new BasicExample())); + System.out.println(script); + String expected = loadTextFromClasspath("/basic.fish"); + assertEquals(expected, script); + } + public static class TopLevel { @Option(names = {"-V", "--version"}, help = true) boolean versionRequested; @Option(names = {"-h", "--help"}, help = true) boolean helpRequested; @@ -173,19 +181,33 @@ public static class Sub2Child3 { // } @Test public void nestedSubcommands() throws Exception { - CommandLine hierarchy = new CommandLine(new TopLevel()) - .addSubcommand("sub1", new Sub1()) - .addSubcommand("sub2", new CommandLine(new Sub2()) - .addSubcommand("subsub1", new Sub2Child1()) - .addSubcommand("subsub2", new Sub2Child2()) - .addSubcommand("subsub3", new Sub2Child3()) - ); + CommandLine hierarchy = getNestedSubcommandsCommandLine(); String script = AutoComplete.bash("picocompletion-demo", hierarchy); String expected = format(loadTextFromClasspath("/picocompletion-demo_completion.bash"), CommandLine.VERSION, concat("\" \"", TimeUnit.values())); assertEquals(expected, script); } + @Test + public void nestedSubcommandsFish() throws Exception { + CommandLine hierarchy = getNestedSubcommandsCommandLine(); + String script = AutoComplete.fish("picocompletion-demo", hierarchy); + System.out.println(script); + String expected = loadTextFromClasspath("/picocompletion-demo_completion.fish"); + assertEquals(expected, script); + } + + private static CommandLine getNestedSubcommandsCommandLine() { + CommandLine hierarchy = new CommandLine(new TopLevel()) + .addSubcommand("sub1", new Sub1()) + .addSubcommand("sub2", new CommandLine(new Sub2()) + .addSubcommand("subsub1", new Sub2Child1()) + .addSubcommand("subsub2", new Sub2Child2()) + .addSubcommand("subsub3", new Sub2Child3()) + ); + return hierarchy; + } + @Test public void helpCommand() { CommandLine hierarchy = new CommandLine(new AutoCompleteTest.TopLevel()) diff --git a/src/test/resources/basic.fish b/src/test/resources/basic.fish new file mode 100644 index 000000000..2ac7ce4ef --- /dev/null +++ b/src/test/resources/basic.fish @@ -0,0 +1,5 @@ + +# _picocli_basicExample completion +set -l _picocli_basicExample +complete -c basicExample --condition "not __fish_seen_subcommand_from $_picocli_basicExample" --long-option timeUnit --short-option u --no-files --arguments 'NANOSECONDS MICROSECONDS MILLISECONDS SECONDS MINUTES HOURS DAYS' -d '' +complete -c basicExample --condition "not __fish_seen_subcommand_from $_picocli_basicExample" --long-option timeout --short-option t -d '' diff --git a/src/test/resources/picocompletion-demo_completion.fish b/src/test/resources/picocompletion-demo_completion.fish new file mode 100644 index 000000000..feccfd286 --- /dev/null +++ b/src/test/resources/picocompletion-demo_completion.fish @@ -0,0 +1,49 @@ + +# _picocli_picocompletion_demo completion +set -l _picocli_picocompletion_demo sub1 sub1-alias sub2 sub2-alias +complete -c picocompletion-demo --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo" --long-option version --short-option V -d '' +complete -c picocompletion-demo --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo" --long-option help --short-option h -d '' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo" --arguments sub1 -d 'First level subcommand 1' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub1" --long-option num -d 'a number' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub1" --long-option str -d 'a String' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub1" --long-option candidates --no-files --arguments 'aaa bbb ccc' -d 'with candidates' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo" --arguments sub1-alias -d 'First level subcommand 1' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub1-alias" --long-option num -d 'a number' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub1-alias" --long-option str -d 'a String' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub1-alias" --long-option candidates --no-files --arguments 'aaa bbb ccc' -d 'with candidates' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo" --arguments sub2 -d 'First level subcommand 2' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub2" --long-option num2 -d 'another number' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub2" --long-option directory --short-option d -d 'a directory' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo" --arguments sub2-alias -d 'First level subcommand 2' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub2-alias" --long-option num2 -d 'another number' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub2-alias" --long-option directory --short-option d -d 'a directory' + +# _picocli_picocompletion_demo_sub2 completion +set -l _picocli_picocompletion_demo_sub2 subsub1 sub2child1-alias subsub2 sub2child2-alias subsub3 sub2child3-alias +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo_sub2" --condition '__fish_seen_subcommand_from sub2' --arguments subsub1 -d 'Second level sub-subcommand 1' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from subsub1" --condition '__fish_seen_subcommand_from sub2' --long-option host --short-option h -d 'a host' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo_sub2" --condition '__fish_seen_subcommand_from sub2' --arguments sub2child1-alias -d 'Second level sub-subcommand 1' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub2child1-alias" --condition '__fish_seen_subcommand_from sub2' --long-option host --short-option h -d 'a host' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo_sub2" --condition '__fish_seen_subcommand_from sub2' --arguments subsub2 -d 'Second level sub-subcommand 2' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from subsub2" --condition '__fish_seen_subcommand_from sub2' --long-option timeUnit --short-option u --no-files --arguments 'NANOSECONDS MICROSECONDS MILLISECONDS SECONDS MINUTES HOURS DAYS' -d '' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from subsub2" --condition '__fish_seen_subcommand_from sub2' --long-option timeout --short-option t -d '' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo_sub2" --condition '__fish_seen_subcommand_from sub2' --arguments sub2child2-alias -d 'Second level sub-subcommand 2' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub2child2-alias" --condition '__fish_seen_subcommand_from sub2' --long-option timeUnit --short-option u --no-files --arguments 'NANOSECONDS MICROSECONDS MILLISECONDS SECONDS MINUTES HOURS DAYS' -d '' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub2child2-alias" --condition '__fish_seen_subcommand_from sub2' --long-option timeout --short-option t -d '' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo_sub2" --condition '__fish_seen_subcommand_from sub2' --arguments subsub3 -d 'Second level sub-subcommand 3' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo_sub2" --condition '__fish_seen_subcommand_from sub2' --arguments sub2child3-alias -d 'Second level sub-subcommand 3' + +# _picocli_picocompletion_demo_sub2alias completion +set -l _picocli_picocompletion_demo_sub2alias subsub1 sub2child1-alias subsub2 sub2child2-alias subsub3 sub2child3-alias +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo_sub2alias" --condition '__fish_seen_subcommand_from sub2-alias' --arguments subsub1 -d 'Second level sub-subcommand 1' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from subsub1" --condition '__fish_seen_subcommand_from sub2-alias' --long-option host --short-option h -d 'a host' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo_sub2alias" --condition '__fish_seen_subcommand_from sub2-alias' --arguments sub2child1-alias -d 'Second level sub-subcommand 1' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub2child1-alias" --condition '__fish_seen_subcommand_from sub2-alias' --long-option host --short-option h -d 'a host' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo_sub2alias" --condition '__fish_seen_subcommand_from sub2-alias' --arguments subsub2 -d 'Second level sub-subcommand 2' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from subsub2" --condition '__fish_seen_subcommand_from sub2-alias' --long-option timeUnit --short-option u --no-files --arguments 'NANOSECONDS MICROSECONDS MILLISECONDS SECONDS MINUTES HOURS DAYS' -d '' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from subsub2" --condition '__fish_seen_subcommand_from sub2-alias' --long-option timeout --short-option t -d '' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo_sub2alias" --condition '__fish_seen_subcommand_from sub2-alias' --arguments sub2child2-alias -d 'Second level sub-subcommand 2' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub2child2-alias" --condition '__fish_seen_subcommand_from sub2-alias' --long-option timeUnit --short-option u --no-files --arguments 'NANOSECONDS MICROSECONDS MILLISECONDS SECONDS MINUTES HOURS DAYS' -d '' +complete -c picocompletion-demo --condition "__fish_seen_subcommand_from sub2child2-alias" --condition '__fish_seen_subcommand_from sub2-alias' --long-option timeout --short-option t -d '' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo_sub2alias" --condition '__fish_seen_subcommand_from sub2-alias' --arguments subsub3 -d 'Second level sub-subcommand 3' +complete -c picocompletion-demo --no-files --condition "not __fish_seen_subcommand_from $_picocli_picocompletion_demo_sub2alias" --condition '__fish_seen_subcommand_from sub2-alias' --arguments sub2child3-alias -d 'Second level sub-subcommand 3'