Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f8e03db

Browse filesBrowse files
committed
[Console] Add completion values to input definition
1 parent 098ff62 commit f8e03db
Copy full SHA for f8e03db

File tree

7 files changed

+103
-49
lines changed
Filter options

7 files changed

+103
-49
lines changed

‎src/Symfony/Component/Console/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Add method `__toString()` to `InputInterface`
8+
* Add completion values for arguments and options in input definition
89

910
6.0
1011
---

‎src/Symfony/Component/Console/Command/Command.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Command/Command.php
+51Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,27 @@ public function run(InputInterface $input, OutputInterface $output): int
303303
*/
304304
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
305305
{
306+
$definition = $this->getDefinition();
307+
$values = null;
308+
if (CompletionInput::TYPE_OPTION_VALUE === $input->getCompletionType() && $definition->hasOption($input->getCompletionName())) {
309+
$values = $definition->getOption($input->getCompletionName())->getValues();
310+
} elseif (CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() && $definition->hasArgument($input->getCompletionName())) {
311+
$values = $definition->getArgument($input->getCompletionName())->getValues();
312+
}
313+
if (null === $values) {
314+
return;
315+
}
316+
if ($values instanceof \Closure) {
317+
$values = $values($input);
318+
if (null === $values) {
319+
return;
320+
}
321+
if (!is_iterable($values)) {
322+
throw new LogicException(sprintf('Callable for "%s" "%s" must return an iterable or null. Got "%s".', $input->getCompletionType(), $input->getCompletionName(), get_debug_type($values)));
323+
}
324+
}
325+
326+
$suggestions->suggestValues(\is_array($values) ? $values : iterator_to_array($values));
306327
}
307328

308329
/**
@@ -426,6 +447,21 @@ public function addArgument(string $name, int $mode = null, string $description
426447
return $this;
427448
}
428449

450+
/**
451+
* Set values for input completion.
452+
*
453+
* @throws InvalidArgumentException If the argument is not defined
454+
*
455+
* @return $this
456+
*/
457+
public function setArgumentValues(string $name, \Closure|iterable|null $values): static
458+
{
459+
$this->definition->getArgument($name)->setValues($values);
460+
$this->fullDefinition?->getArgument($name)->setValues($values);
461+
462+
return $this;
463+
}
464+
429465
/**
430466
* Adds an option.
431467
*
@@ -445,6 +481,21 @@ public function addOption(string $name, string|array $shortcut = null, int $mode
445481
return $this;
446482
}
447483

484+
/**
485+
* Set values for input completion.
486+
*
487+
* @throws InvalidArgumentException If the option is not defined
488+
*
489+
* @return $this
490+
*/
491+
public function setOptionValues(string $name, \Closure|iterable|null $values): static
492+
{
493+
$this->definition->getOption($name)->setValues($values);
494+
$this->fullDefinition?->getOption($name)->setValues($values);
495+
496+
return $this;
497+
}
498+
448499
/**
449500
* Sets the name of the command.
450501
*

‎src/Symfony/Component/Console/Command/DumpCompletionCommand.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Command/DumpCompletionCommand.php
+3-9Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
namespace Symfony\Component\Console\Command;
1313

14-
use Symfony\Component\Console\Completion\CompletionInput;
15-
use Symfony\Component\Console\Completion\CompletionSuggestions;
1614
use Symfony\Component\Console\Input\InputArgument;
1715
use Symfony\Component\Console\Input\InputInterface;
1816
use Symfony\Component\Console\Input\InputOption;
@@ -30,12 +28,7 @@ final class DumpCompletionCommand extends Command
3028
protected static $defaultName = 'completion';
3129
protected static $defaultDescription = 'Dump the shell completion script';
3230

33-
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
34-
{
35-
if ($input->mustSuggestArgumentValuesFor('shell')) {
36-
$suggestions->suggestValues($this->getSupportedShells());
37-
}
38-
}
31+
private array $supportedShells;
3932

4033
protected function configure()
4134
{
@@ -74,6 +67,7 @@ protected function configure()
7467
EOH
7568
)
7669
->addArgument('shell', InputArgument::OPTIONAL, 'The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given')
70+
->setArgumentValues('shell', $this->getSupportedShells())
7771
->addOption('debug', null, InputOption::VALUE_NONE, 'Tail the completion debug log')
7872
;
7973
}
@@ -126,7 +120,7 @@ private function tailDebugLog(string $commandName, OutputInterface $output): voi
126120
*/
127121
private function getSupportedShells(): array
128122
{
129-
return array_map(function ($f) {
123+
return $this->supportedShells ?? $this->supportedShells = array_map(function ($f) {
130124
return pathinfo($f, \PATHINFO_EXTENSION);
131125
}, glob(__DIR__.'/../Resources/completion.*'));
132126
}

‎src/Symfony/Component/Console/Command/HelpCommand.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Command/HelpCommand.php
+6-19Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
namespace Symfony\Component\Console\Command;
1313

14-
use Symfony\Component\Console\Completion\CompletionInput;
15-
use Symfony\Component\Console\Completion\CompletionSuggestions;
1614
use Symfony\Component\Console\Descriptor\ApplicationDescription;
1715
use Symfony\Component\Console\Helper\DescriptorHelper;
1816
use Symfony\Component\Console\Input\InputArgument;
@@ -39,8 +37,12 @@ protected function configure()
3937
$this
4038
->setName('help')
4139
->setDefinition([
42-
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'),
43-
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
40+
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help', function () {
41+
return array_keys((new ApplicationDescription($this->getApplication()))->getCommands());
42+
}),
43+
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', function () {
44+
return (new DescriptorHelper())->getFormats();
45+
}),
4446
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
4547
])
4648
->setDescription('Display help for a command')
@@ -81,19 +83,4 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8183

8284
return 0;
8385
}
84-
85-
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
86-
{
87-
if ($input->mustSuggestArgumentValuesFor('command_name')) {
88-
$descriptor = new ApplicationDescription($this->getApplication());
89-
$suggestions->suggestValues(array_keys($descriptor->getCommands()));
90-
91-
return;
92-
}
93-
94-
if ($input->mustSuggestOptionValuesFor('format')) {
95-
$helper = new DescriptorHelper();
96-
$suggestions->suggestValues($helper->getFormats());
97-
}
98-
}
9986
}

‎src/Symfony/Component/Console/Command/ListCommand.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Command/ListCommand.php
+6-19Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
namespace Symfony\Component\Console\Command;
1313

14-
use Symfony\Component\Console\Completion\CompletionInput;
15-
use Symfony\Component\Console\Completion\CompletionSuggestions;
1614
use Symfony\Component\Console\Descriptor\ApplicationDescription;
1715
use Symfony\Component\Console\Helper\DescriptorHelper;
1816
use Symfony\Component\Console\Input\InputArgument;
@@ -35,9 +33,13 @@ protected function configure()
3533
$this
3634
->setName('list')
3735
->setDefinition([
38-
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
36+
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name', null, function () {
37+
return array_keys((new ApplicationDescription($this->getApplication()))->getNamespaces());
38+
}),
3939
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
40-
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
40+
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', function () {
41+
return (new DescriptorHelper())->getFormats();
42+
}),
4143
new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments'),
4244
])
4345
->setDescription('List commands')
@@ -77,19 +79,4 @@ protected function execute(InputInterface $input, OutputInterface $output): int
7779

7880
return 0;
7981
}
80-
81-
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
82-
{
83-
if ($input->mustSuggestArgumentValuesFor('namespace')) {
84-
$descriptor = new ApplicationDescription($this->getApplication());
85-
$suggestions->suggestValues(array_keys($descriptor->getNamespaces()));
86-
87-
return;
88-
}
89-
90-
if ($input->mustSuggestOptionValuesFor('format')) {
91-
$helper = new DescriptorHelper();
92-
$suggestions->suggestValues($helper->getFormats());
93-
}
94-
}
9582
}

‎src/Symfony/Component/Console/Input/InputArgument.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Input/InputArgument.php
+16-1Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class InputArgument
2828
private string $name;
2929
private int $mode;
3030
private string|int|bool|array|null|float $default;
31+
private \Closure|iterable|null $values;
3132
private string $description;
3233

3334
/**
@@ -38,7 +39,7 @@ class InputArgument
3839
*
3940
* @throws InvalidArgumentException When argument mode is not valid
4041
*/
41-
public function __construct(string $name, int $mode = null, string $description = '', string|bool|int|float|array $default = null)
42+
public function __construct(string $name, int $mode = null, string $description = '', string|bool|int|float|array $default = null, \Closure|iterable|null $values = null)
4243
{
4344
if (null === $mode) {
4445
$mode = self::OPTIONAL;
@@ -51,6 +52,7 @@ public function __construct(string $name, int $mode = null, string $description
5152
$this->description = $description;
5253

5354
$this->setDefault($default);
55+
$this->setValues($values);
5456
}
5557

5658
/**
@@ -111,6 +113,19 @@ public function getDefault(): string|bool|int|float|array|null
111113
return $this->default;
112114
}
113115

116+
public function setValues(\Closure|iterable|null $values = null)
117+
{
118+
$this->values = $values;
119+
}
120+
121+
/**
122+
* Returns suggestion values for input completion.
123+
*/
124+
public function getValues(): \Closure|iterable|null
125+
{
126+
return $this->values;
127+
}
128+
114129
/**
115130
* Returns the description text.
116131
*/

‎src/Symfony/Component/Console/Input/InputOption.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Input/InputOption.php
+20-1Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class InputOption
5050
private string|array|null $shortcut;
5151
private int $mode;
5252
private string|int|bool|array|null|float $default;
53+
private \Closure|iterable|null $values;
5354
private string $description;
5455

5556
/**
@@ -59,7 +60,7 @@ class InputOption
5960
*
6061
* @throws InvalidArgumentException If option mode is invalid or incompatible
6162
*/
62-
public function __construct(string $name, string|array $shortcut = null, int $mode = null, string $description = '', string|bool|int|float|array $default = null)
63+
public function __construct(string $name, string|array $shortcut = null, int $mode = null, string $description = '', string|bool|int|float|array $default = null, \Closure|iterable|null $values = null)
6364
{
6465
if (str_starts_with($name, '--')) {
6566
$name = substr($name, 2);
@@ -105,6 +106,7 @@ public function __construct(string $name, string|array $shortcut = null, int $mo
105106
}
106107

107108
$this->setDefault($default);
109+
$this->setValues($values);
108110
}
109111

110112
/**
@@ -193,6 +195,23 @@ public function getDefault(): string|bool|int|float|array|null
193195
return $this->default;
194196
}
195197

198+
public function setValues(\Closure|iterable|null $values = null)
199+
{
200+
if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $values) {
201+
throw new LogicException('Cannot set a completion when using InputOption::VALUE_NONE mode.');
202+
}
203+
204+
$this->values = $values;
205+
}
206+
207+
/**
208+
* Returns suggestions for input completion.
209+
*/
210+
public function getValues(): \Closure|iterable|null
211+
{
212+
return $this->values;
213+
}
214+
196215
/**
197216
* Returns the description text.
198217
*/

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.