PluginProbe
Depicter — Popup & Slider Builder / trunk
Depicter — Popup & Slider Builder vtrunk
4.8.1 trunk 1.0.0 1.1.0 1.1.2 1.1.4 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.5 1.3.8 1.5.0 1.5.1 1.5.2 1.5.5 1.6.0 1.6.1 1.6.2 1.7.0 All 76 releases
depicter / vendor / symfony / console / Command / CompleteCommand.php

CompleteCommand.php in Depicter — Popup & Slider Builder trunk, at vendor/symfony/console/Command/CompleteCommand.php

206 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Symfony\Component\Console\Command;
13
14 use Symfony\Component\Console\Completion\CompletionInput;
15 use Symfony\Component\Console\Completion\CompletionSuggestions;
16 use Symfony\Component\Console\Completion\Output\BashCompletionOutput;
17 use Symfony\Component\Console\Completion\Output\CompletionOutputInterface;
18 use Symfony\Component\Console\Exception\CommandNotFoundException;
19 use Symfony\Component\Console\Exception\ExceptionInterface;
20 use Symfony\Component\Console\Input\InputInterface;
21 use Symfony\Component\Console\Input\InputOption;
22 use Symfony\Component\Console\Output\OutputInterface;
23
24 /**
25 * Responsible for providing the values to the shell completion.
26 *
27 * @author Wouter de Jong <wouter@wouterj.nl>
28 */
29 final class CompleteCommand extends Command
30 {
31 protected static $defaultName = '|_complete';
32 protected static $defaultDescription = 'Internal command to provide shell completion suggestions';
33
34 private $completionOutputs;
35
36 private $isDebug = false;
37
38 /**
39 * @param array<string, class-string<CompletionOutputInterface>> $completionOutputs A list of additional completion outputs, with shell name as key and FQCN as value
40 */
41 public function __construct(array $completionOutputs = [])
42 {
43 // must be set before the parent constructor, as the property value is used in configure()
44 $this->completionOutputs = $completionOutputs + ['bash' => BashCompletionOutput::class];
45
46 parent::__construct();
47 }
48
49 protected function configure(): void
50 {
51 $this
52 ->addOption('shell', 's', InputOption::VALUE_REQUIRED, 'The shell type ("'.implode('", "', array_keys($this->completionOutputs)).'")')
53 ->addOption('input', 'i', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'An array of input tokens (e.g. COMP_WORDS or argv)')
54 ->addOption('current', 'c', InputOption::VALUE_REQUIRED, 'The index of the "input" array that the cursor is in (e.g. COMP_CWORD)')
55 ->addOption('symfony', 'S', InputOption::VALUE_REQUIRED, 'The version of the completion script')
56 ;
57 }
58
59 protected function initialize(InputInterface $input, OutputInterface $output)
60 {
61 $this->isDebug = filter_var(getenv('SYMFONY_COMPLETION_DEBUG'), \FILTER_VALIDATE_BOOLEAN);
62 }
63
64 protected function execute(InputInterface $input, OutputInterface $output): int
65 {
66 try {
67 // uncomment when a bugfix or BC break has been introduced in the shell completion scripts
68 // $version = $input->getOption('symfony');
69 // if ($version && version_compare($version, 'x.y', '>=')) {
70 // $message = sprintf('Completion script version is not supported ("%s" given, ">=x.y" required).', $version);
71 // $this->log($message);
72
73 // $output->writeln($message.' Install the Symfony completion script again by using the "completion" command.');
74
75 // return 126;
76 // }
77
78 $shell = $input->getOption('shell');
79 if (!$shell) {
80 throw new \RuntimeException('The "--shell" option must be set.');
81 }
82
83 if (!$completionOutput = $this->completionOutputs[$shell] ?? false) {
84 throw new \RuntimeException(sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs))));
85 }
86
87 $completionInput = $this->createCompletionInput($input);
88 $suggestions = new CompletionSuggestions();
89
90 $this->log([
91 '',
92 '<comment>'.date('Y-m-d H:i:s').'</>',
93 '<info>Input:</> <comment>("|" indicates the cursor position)</>',
94 ' '.(string) $completionInput,
95 '<info>Command:</>',
96 ' '.(string) implode(' ', $_SERVER['argv']),
97 '<info>Messages:</>',
98 ]);
99
100 $command = $this->findCommand($completionInput, $output);
101 if (null === $command) {
102 $this->log(' No command found, completing using the Application class.');
103
104 $this->getApplication()->complete($completionInput, $suggestions);
105 } elseif (
106 $completionInput->mustSuggestArgumentValuesFor('command')
107 && $command->getName() !== $completionInput->getCompletionValue()
108 && !\in_array($completionInput->getCompletionValue(), $command->getAliases(), true)
109 ) {
110 $this->log(' No command found, completing using the Application class.');
111
112 // expand shortcut names ("cache:cl<TAB>") into their full name ("cache:clear")
113 $suggestions->suggestValues(array_filter(array_merge([$command->getName()], $command->getAliases())));
114 } else {
115 $command->mergeApplicationDefinition();
116 $completionInput->bind($command->getDefinition());
117
118 if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) {
119 $this->log(' Completing option names for the <comment>'.\get_class($command instanceof LazyCommand ? $command->getCommand() : $command).'</> command.');
120
121 $suggestions->suggestOptions($command->getDefinition()->getOptions());
122 } else {
123 $this->log([
124 ' Completing using the <comment>'.\get_class($command instanceof LazyCommand ? $command->getCommand() : $command).'</> class.',
125 ' Completing <comment>'.$completionInput->getCompletionType().'</> for <comment>'.$completionInput->getCompletionName().'</>',
126 ]);
127 if (null !== $compval = $completionInput->getCompletionValue()) {
128 $this->log(' Current value: <comment>'.$compval.'</>');
129 }
130
131 $command->complete($completionInput, $suggestions);
132 }
133 }
134
135 /** @var CompletionOutputInterface $completionOutput */
136 $completionOutput = new $completionOutput();
137
138 $this->log('<info>Suggestions:</>');
139 if ($options = $suggestions->getOptionSuggestions()) {
140 $this->log(' --'.implode(' --', array_map(function ($o) { return $o->getName(); }, $options)));
141 } elseif ($values = $suggestions->getValueSuggestions()) {
142 $this->log(' '.implode(' ', $values));
143 } else {
144 $this->log(' <comment>No suggestions were provided</>');
145 }
146
147 $completionOutput->write($suggestions, $output);
148 } catch (\Throwable $e) {
149 $this->log([
150 '<error>Error!</error>',
151 (string) $e,
152 ]);
153
154 if ($output->isDebug()) {
155 throw $e;
156 }
157
158 return 2;
159 }
160
161 return 0;
162 }
163
164 private function createCompletionInput(InputInterface $input): CompletionInput
165 {
166 $currentIndex = $input->getOption('current');
167 if (!$currentIndex || !ctype_digit($currentIndex)) {
168 throw new \RuntimeException('The "--current" option must be set and it must be an integer.');
169 }
170
171 $completionInput = CompletionInput::fromTokens($input->getOption('input'), (int) $currentIndex);
172
173 try {
174 $completionInput->bind($this->getApplication()->getDefinition());
175 } catch (ExceptionInterface $e) {
176 }
177
178 return $completionInput;
179 }
180
181 private function findCommand(CompletionInput $completionInput, OutputInterface $output): ?Command
182 {
183 try {
184 $inputName = $completionInput->getFirstArgument();
185 if (null === $inputName) {
186 return null;
187 }
188
189 return $this->getApplication()->find($inputName);
190 } catch (CommandNotFoundException $e) {
191 }
192
193 return null;
194 }
195
196 private function log($messages): void
197 {
198 if (!$this->isDebug) {
199 return;
200 }
201
202 $commandName = basename($_SERVER['argv'][0]);
203 file_put_contents(sys_get_temp_dir().'/sf_'.$commandName.'.log', implode(\PHP_EOL, (array) $messages).\PHP_EOL, \FILE_APPEND);
204 }
205 }
206