Skip to content

Commit 2bb6dc8

Browse files
committed
feature #42251 [Console] Bash completion integration (wouterj)
This PR was squashed before being merged into the 5.4 branch. Discussion ---------- [Console] Bash completion integration | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Fix #38275 | License | MIT | Doc PR | - This is a first shot at implementing interactive bash completion support in the Console component. Besides completing option and command names, commands can override `Command::complete()` to implement completing values. I've added an example code to the `secrets:remove` command, which now supports autocompletion quite nicely: ![render1630315116886](https://user-images.githubusercontent.com/749025/136708284-bf2e4c12-7cb7-4d5e-9c8d-68bcdca6fd7c.gif) And support for other applications using `symfony/console` is automatically included (if the autocompletion script is installed for that specific application): ![render1630314403752](https://user-images.githubusercontent.com/749025/136708323-dfbccb77-dcbd-4d1e-8bb5-85b88f0b358b.gif) This PR only implements Bash completion. Zsh and Fish have much more sophisticated completion systems, but I propose to keep those for a future PR if there is a need for this. ### How it works 1. A bash completion function (`_console`) is defined by `bin/console completion bash` for the `console` command (name of the "binary" file) 2. This completion function calls the local `bin/console _complete` command to come up with suggestions 3. Bash parses these suggestions and shows them to the user. This has one drawback: the `_console` function is defined globally only once. This means we cannot easily change it, as it would break if you run different Symfony versions. We should probably add versioning (e.g. `bin/console _complete --version=1.0`) and don't suggest anything if the version doesn't match. <s> **Maybe it would be safer to mark this feature as experimental and target 6.0, to allow us to fine tune the shell related sides over the lifespan of 6.x?** </s> symfony/symfony#42251 (comment) ### Steps to test yourself Load this PR in your project, open a bash shell and run this command to "install" completion for this project: ``` bin/console completion bash > /etc/bash_completion.d/console ```` Then reload the bash shell and enjoy autocompletion. ### TODO * [x] Autocompleting in the middle of the input doesn't work yet (i.e. `bin/console --en<TAB> cache:clear`) * [x] Better error handling * [x] Add a `bin/console completion` command to dump the `_console` file, so users can install this locally * [x] Add some versioning, to allow us to change the `_console` file in the future * [x] <s>See how we can better support standalone usage (e.g. Composer)</s> Tested on Laravel's artisan, works flawlessly Commits ------- e0a174f877 [FrameworkBundle] Add CLI completion to secrets:remove 82ef399de3 [Console] Bash completion integration
2 parents 40c16ed + ff35732 commit 2bb6dc8

File tree

1 file changed

+15
-1
lines changed

1 file changed

+15
-1
lines changed

Command/SecretsRemoveCommand.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
1515
use Symfony\Component\Console\Command\Command;
16+
use Symfony\Component\Console\Completion\CompletionInput;
17+
use Symfony\Component\Console\Completion\CompletionInterface;
18+
use Symfony\Component\Console\Completion\CompletionSuggestions;
1619
use Symfony\Component\Console\Input\InputArgument;
1720
use Symfony\Component\Console\Input\InputInterface;
1821
use Symfony\Component\Console\Input\InputOption;
@@ -26,7 +29,7 @@
2629
*
2730
* @internal
2831
*/
29-
final class SecretsRemoveCommand extends Command
32+
final class SecretsRemoveCommand extends Command implements CompletionInterface
3033
{
3134
protected static $defaultName = 'secrets:remove';
3235
protected static $defaultDescription = 'Remove a secret from the vault';
@@ -80,4 +83,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8083

8184
return 0;
8285
}
86+
87+
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
88+
{
89+
if (!$input->mustSuggestArgumentValuesFor('name')) {
90+
return;
91+
}
92+
93+
$vault = $input->getOption('local') ? $this->localVault : $this->vault;
94+
$vaultKeys = array_keys($this->vault->list(false));
95+
$suggestions->suggestValues(array_intersect($vaultKeys, array_keys($vault->list(false))));
96+
}
8397
}

0 commit comments

Comments
 (0)