8000 [Console] Add completion values to input definition · symfony/symfony@dfb4cc6 · GitHub
[go: up one dir, main page]

Skip to content

Commit dfb4cc6

Browse files
committed
[Console] Add completion values to input definition
1 parent 098ff62 commit dfb4cc6

File tree

7 files changed

+103
-43
lines changed

7 files changed

+103
-43
lines changed

src/Symfony/Component/Console/CHANGELOG.md

Lines 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

Lines 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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,7 @@ final class DumpCompletionCommand extends Command
3030
protected static $defaultName = 'completion';
3131
protected static $defaultDescription = 'Dump the shell completion script';
3232

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

4035
protected function configure()
4136
{
@@ -74,6 +69,7 @@ protected function configure()
7469
EOH
7570
)
7671
->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')
72+
->setArgumentValues('shell', $this->getSupportedShells())
7773
->addOption('debug', null, InputOption::VALUE_NONE, 'Tail the completion debug log')
7874
;
7975
}
@@ -126,7 +122,7 @@ private function tailDebugLog(string $commandName, OutputInterface $output): voi
126122
*/
127123
private function getSupportedShells(): array
128124
{
129-
return array_map(function ($f) {
125+
return $this->supportedShells ?? $this->supportedShells = array_map(function ($f) {
130126
return pathinfo($f, \PATHINFO_EXTENSION);
131127
}, glob(__DIR__.'/../Resources/completion.*'));
132128
}

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

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,12 @@ protected function configure()
3939
$this
4040
->setName('help')
4141
->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'),
42+
new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help', function () {
43+
return array_keys((new ApplicationDescription($this->getApplication()))->getCommands());
44+
}),
45+
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', function () {
46+
return (new DescriptorHelper())->getFormats();
47+
}),
4448
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help'),
4549
])
4650
->setDescription('Display help for a command')
@@ -81,19 +85,4 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8185

8286
return 0;
8387
}
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-
}
9988
}

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

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,13 @@ protected function configure()
3535
$this
3636
->setName('list')
3737
->setDefinition([
38-
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
38+
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name', null, function () {
39+
return array_keys((new ApplicationDescription($this->getApplication()))->getNamespaces());
40+
}),
3941
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'),
42+
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', function () {
43+
return (new DescriptorHelper())->getFormats();
44+
}),
4145
new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments'),
4246
])
4347
->setDescription('List commands')
@@ -77,19 +81,4 @@ protected function execute(InputInterface $input, OutputInterface $output): int
7781

7882
return 0;
7983
}
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-
}
9584
}

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

Lines 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(Callable|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

Lines 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 = is_callable($values) ? \Closure::fromCallable($values) : $values;
205+
}
206+
207+
/**
208+
* Returns suggestions for input completion.
209+
*/
210+
public function getValues(): Callable|iterable|null
211+
{
212+
return $this->values;
213+
}
214+
196215
/**
197216
* Returns the description text.
198217
*/

0 commit comments

Comments
 (0)
0