mirror of
https://gitlab.com/signalytic/client-external/streamline/streamline-emr.git
synced 2026-09-12 11:11:31 +00:00
The official image from streamline does not currently work for the arm64 platform. As a temporary measure, the source code and docker build scripts have been lifted from the official images and are used to build locally. Some additional modifications are made to reduce overall image size, these are documented in docker/README.md
249 lines
7.9 KiB
PHP
249 lines
7.9 KiB
PHP
<?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);
|
|
}
|
|
}
|