[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <[email protected]> 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\Completion; 13 14 use Symfony\Component\Console\Exception\RuntimeException; 15 use Symfony\Component\Console\Input\ArgvInput; 16 use Symfony\Component\Console\Input\InputDefinition; 17 use Symfony\Component\Console\Input\InputOption; 18 19 /** 20 * An input specialized for shell completion. 21 * 22 * This input allows unfinished option names or values and exposes what kind of 23 * completion is expected. 24 * 25 * @author Wouter de Jong <[email protected]> 26 */ 27 final class CompletionInput extends ArgvInput 28 { 29 public const TYPE_ARGUMENT_VALUE = 'argument_value'; 30 public const TYPE_OPTION_VALUE = 'option_value'; 31 public const TYPE_OPTION_NAME = 'option_name'; 32 public const TYPE_NONE = 'none'; 33 34 private $tokens; 35 private $currentIndex; 36 private $completionType; 37 private $completionName = null; 38 private $completionValue = ''; 39 40 /** 41 * Converts a terminal string into tokens. 42 * 43 * This is required for shell completions without COMP_WORDS support. 44 */ 45 public static function fromString(string $inputStr, int $currentIndex): self 46 { 47 preg_match_all('/(?<=^|\s)([\'"]?)(.+?)(?<!\\\\)\1(?=$|\s)/', $inputStr, $tokens); 48 49 return self::fromTokens($tokens[0], $currentIndex); 50 } 51 52 /** 53 * Create an input based on an COMP_WORDS token list. 54 * 55 * @param string[] $tokens the set of split tokens (e.g. COMP_WORDS or argv) 56 * @param $currentIndex the index of the cursor (e.g. COMP_CWORD) 57 */ 58 public static function fromTokens(array $tokens, int $currentIndex): self 59 { 60 $input = new self($tokens); 61 $input->tokens = $tokens; 62 $input->currentIndex = $currentIndex; 63 64 return $input; 65 } 66 67 /** 68 * {@inheritdoc} 69 */ 70 public function bind(InputDefinition $definition): void 71 { 72 parent::bind($definition); 73 74 $relevantToken = $this->getRelevantToken(); 75 if ('-' === $relevantToken[0]) { 76 // the current token is an input option: complete either option name or option value 77 [$optionToken, $optionValue] = explode('=', $relevantToken, 2) + ['', '']; 78 79 $option = $this->getOptionFromToken($optionToken); 80 if (null === $option && !$this->isCursorFree()) { 81 $this->completionType = self::TYPE_OPTION_NAME; 82 $this->completionValue = $relevantToken; 83 84 return; 85 } 86 87 if (null !== $option && $option->acceptValue()) { 88 $this->completionType = self::TYPE_OPTION_VALUE; 89 $this->completionName = $option->getName(); 90 $this->completionValue = $optionValue ?: (!str_starts_with($optionToken, '--') ? substr($optionToken, 2) : ''); 91 92 return; 93 } 94 } 95 96 $previousToken = $this->tokens[$this->currentIndex - 1]; 97 if ('-' === $previousToken[0] && '' !== trim($previousToken, '-')) { 98 // check if previous option accepted a value 99 $previousOption = $this->getOptionFromToken($previousToken); 100 if (null !== $previousOption && $previousOption->acceptValue()) { 101 $this->completionType = self::TYPE_OPTION_VALUE; 102 $this->completionName = $previousOption->getName(); 103 $this->completionValue = $relevantToken; 104 105 return; 106 } 107 } 108 109 // complete argument value 110 $this->completionType = self::TYPE_ARGUMENT_VALUE; 111 112 foreach ($this->definition->getArguments() as $argumentName => $argument) { 113 if (!isset($this->arguments[$argumentName])) { 114 break; 115 } 116 117 $argumentValue = $this->arguments[$argumentName]; 118 $this->completionName = $argumentName; 119 if (\is_array($argumentValue)) { 120 $this->completionValue = $argumentValue ? $argumentValue[array_key_last($argumentValue)] : null; 121 } else { 122 $this->completionValue = $argumentValue; 123 } 124 } 125 126 if ($this->currentIndex >= \count($this->tokens)) { 127 if (!isset($this->arguments[$argumentName]) || $this->definition->getArgument($argumentName)->isArray()) { 128 $this->completionName = $argumentName; 129 $this->completionValue = ''; 130 } else { 131 // we've reached the end 132 $this->completionType = self::TYPE_NONE; 133 $this->completionName = null; 134 $this->completionValue = ''; 135 } 136 } 137 } 138 139 /** 140 * Returns the type of completion required. 141 * 142 * TYPE_ARGUMENT_VALUE when completing the value of an input argument 143 * TYPE_OPTION_VALUE when completing the value of an input option 144 * TYPE_OPTION_NAME when completing the name of an input option 145 * TYPE_NONE when nothing should be completed 146 * 147 * @return string One of self::TYPE_* constants. TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component 148 */ 149 public function getCompletionType(): string 150 { 151 return $this->completionType; 152 } 153 154 /** 155 * The name of the input option or argument when completing a value. 156 * 157 * @return string|null returns null when completing an option name 158 */ 159 public function getCompletionName(): ?string 160 { 161 return $this->completionName; 162 } 163 164 /** 165 * The value already typed by the user (or empty string). 166 */ 167 public function getCompletionValue(): string 168 { 169 return $this->completionValue; 170 } 171 172 public function mustSuggestOptionValuesFor(string $optionName): bool 173 { 174 return self::TYPE_OPTION_VALUE === $this->getCompletionType() && $optionName === $this->getCompletionName(); 175 } 176 177 public function mustSuggestArgumentValuesFor(string $argumentName): bool 178 { 179 return self::TYPE_ARGUMENT_VALUE === $this->getCompletionType() && $argumentName === $this->getCompletionName(); 180 } 181 182 protected function parseToken(string $token, bool $parseOptions): bool 183 { 184 try { 185 return parent::parseToken($token, $parseOptions); 186 } catch (RuntimeException $e) { 187 // suppress errors, completed input is almost never valid 188 } 189 190 return $parseOptions; 191 } 192 193 private function getOptionFromToken(string $optionToken): ?InputOption 194 { 195 $optionName = ltrim($optionToken, '-'); 196 if (!$optionName) { 197 return null; 198 } 199 200 if ('-' === ($optionToken[1] ?? ' ')) { 201 // long option name 202 return $this->definition->hasOption($optionName) ? $this->definition->getOption($optionName) : null; 203 } 204 205 // short option name 206 return $this->definition->hasShortcut($optionName[0]) ? $this->definition->getOptionForShortcut($optionName[0]) : null; 207 } 208 209 /** 210 * The token of the cursor, or the last token if the cursor is at the end of the input. 211 */ 212 private function getRelevantToken(): string 213 { 214 return $this->tokens[$this->isCursorFree() ? $this->currentIndex - 1 : $this->currentIndex]; 215 } 216 217 /** 218 * Whether the cursor is "free" (i.e. at the end of the input preceded by a space). 219 */ 220 private function isCursorFree(): bool 221 { 222 $nrOfTokens = \count($this->tokens); 223 if ($this->currentIndex > $nrOfTokens) { 224 throw new \LogicException('Current index is invalid, it must be the number of input tokens or one more.'); 225 } 226 227 return $this->currentIndex >= $nrOfTokens; 228 } 229 230 public function __toString() 231 { 232 $str = ''; 233 foreach ($this->tokens as $i => $token) { 234 $str .= $token; 235 236 if ($this->currentIndex === $i) { 237 $str .= '|'; 238 } 239 240 $str .= ' '; 241 } 242 243 if ($this->currentIndex > $i) { 244 $str .= '|'; 245 } 246 247 return rtrim($str); 248 } 249 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |