feature #39904 [Console] add option --short to the list command (nicolas-grekas)

This PR was merged into the 5.3-dev branch.

Discussion
----------

[Console] add option `--short` to the `list` command

| Q             | A
| ------------- | ---
| Branch?       | 5.x
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

This PR is a follow up of https://github.com/symfony/symfony/pull/39851, triggered by @wouterj's comment at https://github.com/symfony/symfony/pull/39851#pullrequestreview-572147186.

This new option should enable creating fast shell auto-completion, by allowing the `list` command to run fast.

Commits
-------

81d5728f4a [Console] add option `--short` to the `list` command
This commit is contained in:
Robin Chalas 2021-01-20 17:38:21 +01:00
commit dc9db1e66f
20 changed files with 132 additions and 35 deletions

View File

@ -31,6 +31,7 @@ class DebugAutowiringCommand extends ContainerDebugCommand
{ {
protected static $defaultName = 'debug:autowiring'; protected static $defaultName = 'debug:autowiring';
protected static $defaultDescription = 'Lists classes/interfaces you can use for autowiring'; protected static $defaultDescription = 'Lists classes/interfaces you can use for autowiring';
private $supportsHref; private $supportsHref;
private $fileLinkFormatter; private $fileLinkFormatter;

View File

@ -25,6 +25,7 @@ use Symfony\Component\Translation\Command\XliffLintCommand as BaseLintCommand;
class XliffLintCommand extends BaseLintCommand class XliffLintCommand extends BaseLintCommand
{ {
protected static $defaultName = 'lint:xliff'; protected static $defaultName = 'lint:xliff';
protected static $defaultDescription = 'Lints a XLIFF file and outputs encountered errors';
public function __construct() public function __construct()
{ {

View File

@ -24,6 +24,7 @@ use Symfony\Component\Yaml\Command\LintCommand as BaseLintCommand;
class YamlLintCommand extends BaseLintCommand class YamlLintCommand extends BaseLintCommand
{ {
protected static $defaultName = 'lint:yaml'; protected static $defaultName = 'lint:yaml';
protected static $defaultDescription = 'Lints a file and outputs encountered errors';
public function __construct() public function __construct()
{ {

View File

@ -22,6 +22,9 @@ use Symfony\Component\Finder\Finder;
*/ */
final class LintCommand extends BaseLintCommand final class LintCommand extends BaseLintCommand
{ {
protected static $defaultName = 'lint:twig';
protected static $defaultDescription = 'Lints a template and outputs encountered errors';
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@ -8,6 +8,7 @@ CHANGELOG
* Add `InputOption::VALUE_NEGATABLE` flag to handle `--foo`/`--no-foo` options * Add `InputOption::VALUE_NEGATABLE` flag to handle `--foo`/`--no-foo` options
* Add the `Command::$defaultDescription` static property and the `description` attribute * Add the `Command::$defaultDescription` static property and the `description` attribute
on the `console.command` tag to allow the `list` command to instantiate commands lazily on the `console.command` tag to allow the `list` command to instantiate commands lazily
* Add option `--short` to the `list` command
5.2.0 5.2.0
----- -----

View File

@ -35,6 +35,7 @@ class ListCommand extends Command
new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'), new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'),
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'),
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'),
new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments'),
]) ])
->setDescription('Lists commands') ->setDescription('Lists commands')
->setHelp(<<<'EOF' ->setHelp(<<<'EOF'
@ -68,6 +69,7 @@ EOF
'format' => $input->getOption('format'), 'format' => $input->getOption('format'),
'raw_text' => $input->getOption('raw'), 'raw_text' => $input->getOption('raw'),
'namespace' => $input->getArgument('namespace'), 'namespace' => $input->getArgument('namespace'),
'short' => $input->getOption('short'),
]); ]);
return 0; return 0;

View File

@ -58,7 +58,7 @@ class JsonDescriptor extends Descriptor
*/ */
protected function describeCommand(Command $command, array $options = []) protected function describeCommand(Command $command, array $options = [])
{ {
$this->writeData($this->getCommandData($command), $options); $this->writeData($this->getCommandData($command, $options['short'] ?? false), $options);
} }
/** /**
@ -71,7 +71,7 @@ class JsonDescriptor extends Descriptor
$commands = []; $commands = [];
foreach ($description->getCommands() as $command) { foreach ($description->getCommands() as $command) {
$commands[] = $this->getCommandData($command); $commands[] = $this->getCommandData($command, $options['short'] ?? false);
} }
$data = []; $data = [];
@ -153,17 +153,29 @@ class JsonDescriptor extends Descriptor
return ['arguments' => $inputArguments, 'options' => $inputOptions]; return ['arguments' => $inputArguments, 'options' => $inputOptions];
} }
private function getCommandData(Command $command): array private function getCommandData(Command $command, bool $short = false): array
{ {
$data = [
'name' => $command->getName(),
'description' => $command->getDescription(),
];
if ($short) {
$data += [
'usage' => $command->getAliases(),
];
} else {
$command->mergeApplicationDefinition(false); $command->mergeApplicationDefinition(false);
return [ $data += [
'name' => $command->getName(),
'usage' => array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()), 'usage' => array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()),
'description' => $command->getDescription(),
'help' => $command->getProcessedHelp(), 'help' => $command->getProcessedHelp(),
'definition' => $this->getInputDefinitionData($command->getDefinition()), 'definition' => $this->getInputDefinitionData($command->getDefinition()),
'hidden' => $command->isHidden(),
]; ];
} }
$data['hidden'] = $command->isHidden();
return $data;
}
} }

View File

@ -122,6 +122,20 @@ class MarkdownDescriptor extends Descriptor
*/ */
protected function describeCommand(Command $command, array $options = []) protected function describeCommand(Command $command, array $options = [])
{ {
if ($options['short'] ?? false) {
$this->write(
'`'.$command->getName()."`\n"
.str_repeat('-', Helper::strlen($command->getName()) + 2)."\n\n"
.($command->getDescription() ? $command->getDescription()."\n\n" : '')
.'### Usage'."\n\n"
.array_reduce($command->getAliases(), function ($carry, $usage) {
return $carry.'* `'.$usage.'`'."\n";
})
);
return;
}
$command->mergeApplicationDefinition(false); $command->mergeApplicationDefinition(false);
$this->write( $this->write(
@ -171,7 +185,7 @@ class MarkdownDescriptor extends Descriptor
foreach ($description->getCommands() as $command) { foreach ($description->getCommands() as $command) {
$this->write("\n\n"); $this->write("\n\n");
if (null !== $describeCommand = $this->describeCommand($command)) { if (null !== $describeCommand = $this->describeCommand($command, $options)) {
$this->write($describeCommand); $this->write($describeCommand);
} }
} }

View File

@ -44,36 +44,42 @@ class XmlDescriptor extends Descriptor
return $dom; return $dom;
} }
public function getCommandDocument(Command $command): \DOMDocument public function getCommandDocument(Command $command, bool $short = false): \DOMDocument
{ {
$dom = new \DOMDocument('1.0', 'UTF-8'); $dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($commandXML = $dom->createElement('command')); $dom->appendChild($commandXML = $dom->createElement('command'));
$command->mergeApplicationDefinition(false);
$commandXML->setAttribute('id', $command->getName()); $commandXML->setAttribute('id', $command->getName());
$commandXML->setAttribute('name', $command->getName()); $commandXML->setAttribute('name', $command->getName());
$commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0); $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0);
$commandXML->appendChild($usagesXML = $dom->createElement('usages')); $commandXML->appendChild($usagesXML = $dom->createElement('usages'));
$commandXML->appendChild($descriptionXML = $dom->createElement('description'));
$descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription())));
if ($short) {
foreach ($command->getAliases() as $usage) {
$usagesXML->appendChild($dom->createElement('usage', $usage));
}
} else {
$command->mergeApplicationDefinition(false);
foreach (array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) { foreach (array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) {
$usagesXML->appendChild($dom->createElement('usage', $usage)); $usagesXML->appendChild($dom->createElement('usage', $usage));
} }
$commandXML->appendChild($descriptionXML = $dom->createElement('description'));
$descriptionXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getDescription())));
$commandXML->appendChild($helpXML = $dom->createElement('help')); $commandXML->appendChild($helpXML = $dom->createElement('help'));
$helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp()))); $helpXML->appendChild($dom->createTextNode(str_replace("\n", "\n ", $command->getProcessedHelp())));
$definitionXML = $this->getInputDefinitionDocument($command->getDefinition()); $definitionXML = $this->getInputDefinitionDocument($command->getDefinition());
$this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0)); $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0));
}
return $dom; return $dom;
} }
public function getApplicationDocument(Application $application, string $namespace = null): \DOMDocument public function getApplicationDocument(Application $application, string $namespace = null, bool $short = false): \DOMDocument
{ {
$dom = new \DOMDocument('1.0', 'UTF-8'); $dom = new \DOMDocument('1.0', 'UTF-8');
$dom->appendChild($rootXml = $dom->createElement('symfony')); $dom->appendChild($rootXml = $dom->createElement('symfony'));
@ -94,7 +100,7 @@ class XmlDescriptor extends Descriptor
} }
foreach ($description->getCommands() as $command) { foreach ($description->getCommands() as $command) {
$this->appendDocument($commandsXML, $this->getCommandDocument($command)); $this->appendDocument($commandsXML, $this->getCommandDocument($command, $short));
} }
if (!$namespace) { if (!$namespace) {
@ -143,7 +149,7 @@ class XmlDescriptor extends Descriptor
*/ */
protected function describeCommand(Command $command, array $options = []) protected function describeCommand(Command $command, array $options = [])
{ {
$this->writeDocument($this->getCommandDocument($command)); $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? false));
} }
/** /**
@ -151,7 +157,7 @@ class XmlDescriptor extends Descriptor
*/ */
protected function describeApplication(Application $application, array $options = []) protected function describeApplication(Application $application, array $options = [])
{ {
$this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null)); $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? false));
} }
/** /**

View File

@ -65,7 +65,7 @@ class HelpCommandTest extends TestCase
$application = new Application(); $application = new Application();
$commandTester = new CommandTester($application->get('help')); $commandTester = new CommandTester($application->get('help'));
$commandTester->execute(['command_name' => 'list', '--format' => 'xml']); $commandTester->execute(['command_name' => 'list', '--format' => 'xml']);
$this->assertStringContainsString('list [--raw] [--format FORMAT] [--] [&lt;namespace&gt;]', $commandTester->getDisplay(), '->execute() returns a text help for the given command'); $this->assertStringContainsString('list [--raw] [--format FORMAT] [--short] [--] [&lt;namespace&gt;]', $commandTester->getDisplay(), '->execute() returns a text help for the given command');
$this->assertStringContainsString('<command', $commandTester->getDisplay(), '->execute() returns an XML help text if --format=xml is passed'); $this->assertStringContainsString('<command', $commandTester->getDisplay(), '->execute() returns an XML help text if --format=xml is passed');
} }
} }

View File

@ -107,7 +107,7 @@
"name": "list", "name": "list",
"hidden": false, "hidden": false,
"usage": [ "usage": [
"list [--raw] [--format FORMAT] [--] [<namespace>]" "list [--raw] [--format FORMAT] [--short] [--] [<namespace>]"
], ],
"description": "Lists commands", "description": "Lists commands",
"help": "The <info>list<\/info> command lists all commands:\n\n <info>app\/console list<\/info>\n\nYou can also display the commands for a specific namespace:\n\n <info>app\/console list test<\/info>\n\nYou can also output the information in other formats by using the <comment>--format<\/comment> option:\n\n <info>app\/console list --format=xml<\/info>\n\nIt's also possible to get raw list of commands (useful for embedding command runner):\n\n <info>app\/console list --raw<\/info>", "help": "The <info>list<\/info> command lists all commands:\n\n <info>app\/console list<\/info>\n\nYou can also display the commands for a specific namespace:\n\n <info>app\/console list test<\/info>\n\nYou can also output the information in other formats by using the <comment>--format<\/comment> option:\n\n <info>app\/console list --format=xml<\/info>\n\nIt's also possible to get raw list of commands (useful for embedding command runner):\n\n <info>app\/console list --raw<\/info>",
@ -202,6 +202,15 @@
"is_multiple": false, "is_multiple": false,
"description": "Do not ask any interactive question", "description": "Do not ask any interactive question",
"default": false "default": false
},
"short": {
"name": "--short",
"shortcut": "",
"accept_value": false,
"is_value_required": false,
"is_multiple": false,
"description": "To skip describing commands' arguments",
"default": false
} }
} }
} }

View File

@ -122,7 +122,7 @@ Lists commands
### Usage ### Usage
* `list [--raw] [--format FORMAT] [--] [<namespace>]` * `list [--raw] [--format FORMAT] [--short] [--] [<namespace>]`
The list command lists all commands: The list command lists all commands:
@ -172,6 +172,16 @@ The output format (txt, xml, json, or md)
* Is negatable: no * Is negatable: no
* Default: `'txt'` * Default: `'txt'`
#### `--short`
To skip describing commands' arguments
* Accept value: no
* Is value required: no
* Is multiple: no
* Is negatable: no
* Default: `false`
#### `--help|-h` #### `--help|-h`
Display help for the given command. When no command is given display help for the list command Display help for the given command. When no command is given display help for the list command

View File

@ -58,7 +58,7 @@
</command> </command>
<command id="list" name="list" hidden="0"> <command id="list" name="list" hidden="0">
<usages> <usages>
<usage>list [--raw] [--format FORMAT] [--] [&lt;namespace&gt;]</usage> <usage>list [--raw] [--format FORMAT] [--short] [--] [&lt;namespace&gt;]</usage>
</usages> </usages>
<description>Lists commands</description> <description>Lists commands</description>
<help>The &lt;info&gt;list&lt;/info&gt; command lists all commands: <help>The &lt;info&gt;list&lt;/info&gt; command lists all commands:
@ -92,6 +92,9 @@
<default>txt</default> <default>txt</default>
</defaults> </defaults>
</option> </option>
<option name="--short" shortcut="" accept_value="0" is_value_required="0" is_multiple="0">
<description>To skip describing commands' arguments</description>
</option>
<option name="--help" shortcut="-h" accept_value="0" is_value_required="0" is_multiple="0"> <option name="--help" shortcut="-h" accept_value="0" is_value_required="0" is_multiple="0">
<description>Display help for the given command. When no command is given display help for the &lt;info&gt;list&lt;/info&gt; command</description> <description>Display help for the given command. When no command is given display help for the &lt;info&gt;list&lt;/info&gt; command</description>
</option> </option>

View File

@ -111,7 +111,7 @@
"name": "list", "name": "list",
"hidden": false, "hidden": false,
"usage": [ "usage": [
"list [--raw] [--format FORMAT] [--] [<namespace>]" "list [--raw] [--format FORMAT] [--short] [--] [<namespace>]"
], ],
"description": "Lists commands", "description": "Lists commands",
"help": "The <info>list<\/info> command lists all commands:\n\n <info>app\/console list<\/info>\n\nYou can also display the commands for a specific namespace:\n\n <info>app\/console list test<\/info>\n\nYou can also output the information in other formats by using the <comment>--format<\/comment> option:\n\n <info>app\/console list --format=xml<\/info>\n\nIt's also possible to get raw list of commands (useful for embedding command runner):\n\n <info>app\/console list --raw<\/info>", "help": "The <info>list<\/info> command lists all commands:\n\n <info>app\/console list<\/info>\n\nYou can also display the commands for a specific namespace:\n\n <info>app\/console list test<\/info>\n\nYou can also output the information in other formats by using the <comment>--format<\/comment> option:\n\n <info>app\/console list --format=xml<\/info>\n\nIt's also possible to get raw list of commands (useful for embedding command runner):\n\n <info>app\/console list --raw<\/info>",
@ -206,6 +206,15 @@
"is_multiple": false, "is_multiple": false,
"description": "Do not ask any interactive question", "description": "Do not ask any interactive question",
"default": false "default": false
},
"short": {
"name": "--short",
"shortcut": "",
"accept_value": false,
"is_value_required": false,
"is_multiple": false,
"description": "To skip describing commands' arguments",
"default": false
} }
} }
} }

View File

@ -135,7 +135,7 @@ Lists commands
### Usage ### Usage
* `list [--raw] [--format FORMAT] [--] [<namespace>]` * `list [--raw] [--format FORMAT] [--short] [--] [<namespace>]`
The list command lists all commands: The list command lists all commands:
@ -185,6 +185,16 @@ The output format (txt, xml, json, or md)
* Is negatable: no * Is negatable: no
* Default: `'txt'` * Default: `'txt'`
#### `--short`
To skip describing commands' arguments
* Accept value: no
* Is value required: no
* Is multiple: no
* Is negatable: no
* Default: `false`
#### `--help|-h` #### `--help|-h`
Display help for the given command. When no command is given display help for the list command Display help for the given command. When no command is given display help for the list command

View File

@ -58,7 +58,7 @@
</command> </command>
<command id="list" name="list" hidden="0"> <command id="list" name="list" hidden="0">
<usages> <usages>
<usage>list [--raw] [--format FORMAT] [--] [&lt;namespace&gt;]</usage> <usage>list [--raw] [--format FORMAT] [--short] [--] [&lt;namespace&gt;]</usage>
</usages> </usages>
<description>Lists commands</description> <description>Lists commands</description>
<help>The &lt;info&gt;list&lt;/info&gt; command lists all commands: <help>The &lt;info&gt;list&lt;/info&gt; command lists all commands:
@ -92,6 +92,9 @@
<default>txt</default> <default>txt</default>
</defaults> </defaults>
</option> </option>
<option name="--short" shortcut="" accept_value="0" is_value_required="0" is_multiple="0">
<description>To skip describing commands' arguments</description>
</option>
<option name="--help" shortcut="-h" accept_value="0" is_value_required="0" is_multiple="0"> <option name="--help" shortcut="-h" accept_value="0" is_value_required="0" is_multiple="0">
<description>Display help for the given command. When no command is given display help for the &lt;info&gt;list&lt;/info&gt; command</description> <description>Display help for the given command. When no command is given display help for the &lt;info&gt;list&lt;/info&gt; command</description>
</option> </option>

View File

@ -126,7 +126,7 @@ Lists commands
### Usage ### Usage
* `list [--raw] [--format FORMAT] [--] [<namespace>]` * `list [--raw] [--format FORMAT] [--short] [--] [<namespace>]`
The list command lists all commands: The list command lists all commands:
@ -176,6 +176,16 @@ The output format (txt, xml, json, or md)
* Is negatable: no * Is negatable: no
* Default: `'txt'` * Default: `'txt'`
#### `--short`
To skip describing commands' arguments
* Accept value: no
* Is value required: no
* Is multiple: no
* Is negatable: no
* Default: `false`
#### `--help|-h` #### `--help|-h`
Display help for the given command. When no command is given display help for the list command Display help for the given command. When no command is given display help for the list command

View File

@ -3,5 +3,5 @@
The "--foo" option does not exist. The "--foo" option does not exist.
list [--raw] [--format FORMAT] [--] [<namespace>] list [--raw] [--format FORMAT] [--short] [--] [<namespace>]

View File

@ -10,6 +10,7 @@ Arguments:
Options: Options:
--raw To output raw command list --raw To output raw command list
--format=FORMAT The output format (txt, xml, json, or md) [default: "txt"] --format=FORMAT The output format (txt, xml, json, or md) [default: "txt"]
--short To skip describing commands' arguments
-h, --help Display help for the given command. When no command is given display help for the list command -h, --help Display help for the given command. When no command is given display help for the list command
-q, --quiet Do not output any message -q, --quiet Do not output any message
-V, --version Display this application version -V, --version Display this application version

View File

@ -10,6 +10,7 @@ Arguments:
Options: Options:
--raw To output raw command list --raw To output raw command list
--format=FORMAT The output format (txt, xml, json, or md) [default: "txt"] --format=FORMAT The output format (txt, xml, json, or md) [default: "txt"]
--short To skip describing commands' arguments
-h, --help Display help for the given command. When no command is given display help for the list command -h, --help Display help for the given command. When no command is given display help for the list command
-q, --quiet Do not output any message -q, --quiet Do not output any message
-V, --version Display this application version -V, --version Display this application version