first commit

This commit is contained in:
Sampanna Rimal
2024-08-27 17:48:06 +05:45
commit 53c0140f58
10839 changed files with 1125847 additions and 0 deletions

View File

@ -0,0 +1,248 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Completion;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
/**
* An input specialized for shell completion.
*
* This input allows unfinished option names or values and exposes what kind of
* completion is expected.
*
* @author Wouter de Jong <wouter@wouterj.nl>
*/
final class CompletionInput extends ArgvInput
{
public const TYPE_ARGUMENT_VALUE = 'argument_value';
public const TYPE_OPTION_VALUE = 'option_value';
public const TYPE_OPTION_NAME = 'option_name';
public const TYPE_NONE = 'none';
private array $tokens;
private int $currentIndex;
private string $completionType;
private ?string $completionName = null;
private string $completionValue = '';
/**
* Converts a terminal string into tokens.
*
* This is required for shell completions without COMP_WORDS support.
*/
public static function fromString(string $inputStr, int $currentIndex): self
{
preg_match_all('/(?<=^|\s)([\'"]?)(.+?)(?<!\\\\)\1(?=$|\s)/', $inputStr, $tokens);
return self::fromTokens($tokens[0], $currentIndex);
}
/**
* Create an input based on an COMP_WORDS token list.
*
* @param string[] $tokens the set of split tokens (e.g. COMP_WORDS or argv)
* @param $currentIndex the index of the cursor (e.g. COMP_CWORD)
*/
public static function fromTokens(array $tokens, int $currentIndex): self
{
$input = new self($tokens);
$input->tokens = $tokens;
$input->currentIndex = $currentIndex;
return $input;
}
public function bind(InputDefinition $definition): void
{
parent::bind($definition);
$relevantToken = $this->getRelevantToken();
if ('-' === $relevantToken[0]) {
// the current token is an input option: complete either option name or option value
[$optionToken, $optionValue] = explode('=', $relevantToken, 2) + ['', ''];
$option = $this->getOptionFromToken($optionToken);
if (null === $option && !$this->isCursorFree()) {
$this->completionType = self::TYPE_OPTION_NAME;
$this->completionValue = $relevantToken;
return;
}
if ($option?->acceptValue()) {
$this->completionType = self::TYPE_OPTION_VALUE;
$this->completionName = $option->getName();
$this->completionValue = $optionValue ?: (!str_starts_with($optionToken, '--') ? substr($optionToken, 2) : '');
return;
}
}
$previousToken = $this->tokens[$this->currentIndex - 1];
if ('-' === $previousToken[0] && '' !== trim($previousToken, '-')) {
// check if previous option accepted a value
$previousOption = $this->getOptionFromToken($previousToken);
if ($previousOption?->acceptValue()) {
$this->completionType = self::TYPE_OPTION_VALUE;
$this->completionName = $previousOption->getName();
$this->completionValue = $relevantToken;
return;
}
}
// complete argument value
$this->completionType = self::TYPE_ARGUMENT_VALUE;
foreach ($this->definition->getArguments() as $argumentName => $argument) {
if (!isset($this->arguments[$argumentName])) {
break;
}
$argumentValue = $this->arguments[$argumentName];
$this->completionName = $argumentName;
if (\is_array($argumentValue)) {
$this->completionValue = $argumentValue ? $argumentValue[array_key_last($argumentValue)] : null;
} else {
$this->completionValue = $argumentValue;
}
}
if ($this->currentIndex >= \count($this->tokens)) {
if (!isset($this->arguments[$argumentName]) || $this->definition->getArgument($argumentName)->isArray()) {
$this->completionName = $argumentName;
$this->completionValue = '';
} else {
// we've reached the end
$this->completionType = self::TYPE_NONE;
$this->completionName = null;
$this->completionValue = '';
}
}
}
/**
* Returns the type of completion required.
*
* TYPE_ARGUMENT_VALUE when completing the value of an input argument
* TYPE_OPTION_VALUE when completing the value of an input option
* TYPE_OPTION_NAME when completing the name of an input option
* TYPE_NONE when nothing should be completed
*
* TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component.
*
* @return self::TYPE_*
*/
public function getCompletionType(): string
{
return $this->completionType;
}
/**
* The name of the input option or argument when completing a value.
*
* @return string|null returns null when completing an option name
*/
public function getCompletionName(): ?string
{
return $this->completionName;
}
/**
* The value already typed by the user (or empty string).
*/
public function getCompletionValue(): string
{
return $this->completionValue;
}
public function mustSuggestOptionValuesFor(string $optionName): bool
{
return self::TYPE_OPTION_VALUE === $this->getCompletionType() && $optionName === $this->getCompletionName();
}
public function mustSuggestArgumentValuesFor(string $argumentName): bool
{
return self::TYPE_ARGUMENT_VALUE === $this->getCompletionType() && $argumentName === $this->getCompletionName();
}
protected function parseToken(string $token, bool $parseOptions): bool
{
try {
return parent::parseToken($token, $parseOptions);
} catch (RuntimeException) {
// suppress errors, completed input is almost never valid
}
return $parseOptions;
}
private function getOptionFromToken(string $optionToken): ?InputOption
{
$optionName = ltrim($optionToken, '-');
if (!$optionName) {
return null;
}
if ('-' === ($optionToken[1] ?? ' ')) {
// long option name
return $this->definition->hasOption($optionName) ? $this->definition->getOption($optionName) : null;
}
// short option name
return $this->definition->hasShortcut($optionName[0]) ? $this->definition->getOptionForShortcut($optionName[0]) : null;
}
/**
* The token of the cursor, or the last token if the cursor is at the end of the input.
*/
private function getRelevantToken(): string
{
return $this->tokens[$this->isCursorFree() ? $this->currentIndex - 1 : $this->currentIndex];
}
/**
* Whether the cursor is "free" (i.e. at the end of the input preceded by a space).
*/
private function isCursorFree(): bool
{
$nrOfTokens = \count($this->tokens);
if ($this->currentIndex > $nrOfTokens) {
throw new \LogicException('Current index is invalid, it must be the number of input tokens or one more.');
}
return $this->currentIndex >= $nrOfTokens;
}
public function __toString()
{
$str = '';
foreach ($this->tokens as $i => $token) {
$str .= $token;
if ($this->currentIndex === $i) {
$str .= '|';
}
$str .= ' ';
}
if ($this->currentIndex > $i) {
$str .= '|';
}
return rtrim($str);
}
}

View File

@ -0,0 +1,97 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Completion;
use Symfony\Component\Console\Input\InputOption;
/**
* Stores all completion suggestions for the current input.
*
* @author Wouter de Jong <wouter@wouterj.nl>
*/
final class CompletionSuggestions
{
private array $valueSuggestions = [];
private array $optionSuggestions = [];
/**
* Add a suggested value for an input option or argument.
*
* @return $this
*/
public function suggestValue(string|Suggestion $value): static
{
$this->valueSuggestions[] = !$value instanceof Suggestion ? new Suggestion($value) : $value;
return $this;
}
/**
* Add multiple suggested values at once for an input option or argument.
*
* @param list<string|Suggestion> $values
*
* @return $this
*/
public function suggestValues(array $values): static
{
foreach ($values as $value) {
$this->suggestValue($value);
}
return $this;
}
/**
* Add a suggestion for an input option name.
*
* @return $this
*/
public function suggestOption(InputOption $option): static
{
$this->optionSuggestions[] = $option;
return $this;
}
/**
* Add multiple suggestions for input option names at once.
*
* @param InputOption[] $options
*
* @return $this
*/
public function suggestOptions(array $options): static
{
foreach ($options as $option) {
$this->suggestOption($option);
}
return $this;
}
/**
* @return InputOption[]
*/
public function getOptionSuggestions(): array
{
return $this->optionSuggestions;
}
/**
* @return Suggestion[]
*/
public function getValueSuggestions(): array
{
return $this->valueSuggestions;
}
}

View File

@ -0,0 +1,33 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Completion\Output;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Wouter de Jong <wouter@wouterj.nl>
*/
class BashCompletionOutput implements CompletionOutputInterface
{
public function write(CompletionSuggestions $suggestions, OutputInterface $output): void
{
$values = $suggestions->getValueSuggestions();
foreach ($suggestions->getOptionSuggestions() as $option) {
$values[] = '--'.$option->getName();
if ($option->isNegatable()) {
$values[] = '--no-'.$option->getName();
}
}
$output->writeln(implode("\n", $values));
}
}

View File

@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Completion\Output;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Transforms the {@see CompletionSuggestions} object into output readable by the shell completion.
*
* @author Wouter de Jong <wouter@wouterj.nl>
*/
interface CompletionOutputInterface
{
public function write(CompletionSuggestions $suggestions, OutputInterface $output): void;
}

View File

@ -0,0 +1,33 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Completion\Output;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Guillaume Aveline <guillaume.aveline@pm.me>
*/
class FishCompletionOutput implements CompletionOutputInterface
{
public function write(CompletionSuggestions $suggestions, OutputInterface $output): void
{
$values = $suggestions->getValueSuggestions();
foreach ($suggestions->getOptionSuggestions() as $option) {
$values[] = '--'.$option->getName();
if ($option->isNegatable()) {
$values[] = '--no-'.$option->getName();
}
}
$output->write(implode("\n", $values));
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Completion\Output;
use Symfony\Component\Console\Completion\CompletionSuggestions;
use Symfony\Component\Console\Output\OutputInterface;
/**
* @author Jitendra A <adhocore@gmail.com>
*/
class ZshCompletionOutput implements CompletionOutputInterface
{
public function write(CompletionSuggestions $suggestions, OutputInterface $output): void
{
$values = [];
foreach ($suggestions->getValueSuggestions() as $value) {
$values[] = $value->getValue().($value->getDescription() ? "\t".$value->getDescription() : '');
}
foreach ($suggestions->getOptionSuggestions() as $option) {
$values[] = '--'.$option->getName().($option->getDescription() ? "\t".$option->getDescription() : '');
if ($option->isNegatable()) {
$values[] = '--no-'.$option->getName().($option->getDescription() ? "\t".$option->getDescription() : '');
}
}
$output->write(implode("\n", $values)."\n");
}
}

View File

@ -0,0 +1,41 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Completion;
/**
* Represents a single suggested value.
*
* @author Wouter de Jong <wouter@wouterj.nl>
*/
class Suggestion implements \Stringable
{
public function __construct(
private readonly string $value,
private readonly string $description = ''
) {
}
public function getValue(): string
{
return $this->value;
}
public function getDescription(): string
{
return $this->description;
}
public function __toString(): string
{
return $this->getValue();
}
}