package and depencies

This commit is contained in:
RafficMohammed
2023-01-08 02:57:24 +05:30
parent d5332eb421
commit 1d54b8bc7f
4309 changed files with 193331 additions and 172289 deletions

View File

@@ -0,0 +1,124 @@
<?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\Output;
use Symfony\Component\Console\Exception\InvalidArgumentException;
/**
* @author Fabien Potencier <fabien@symfony.com>
* @author Julien Boudry <julien@condorcet.vote>
*/
enum AnsiColorMode
{
/*
* Classical 4-bit Ansi colors, including 8 classical colors and 8 bright color. Output syntax is "ESC[${foreGroundColorcode};${backGroundColorcode}m"
* Must be compatible with all terminals and it's the minimal version supported.
*/
case Ansi4;
/*
* 8-bit Ansi colors (240 differents colors + 16 duplicate color codes, ensuring backward compatibility).
* Output syntax is: "ESC[38;5;${foreGroundColorcode};48;5;${backGroundColorcode}m"
* Should be compatible with most terminals.
*/
case Ansi8;
/*
* 24-bit Ansi colors (RGB).
* Output syntax is: "ESC[38;2;${foreGroundColorcodeRed};${foreGroundColorcodeGreen};${foreGroundColorcodeBlue};48;2;${backGroundColorcodeRed};${backGroundColorcodeGreen};${backGroundColorcodeBlue}m"
* May be compatible with many modern terminals.
*/
case Ansi24;
/**
* Converts an RGB hexadecimal color to the corresponding Ansi code.
*/
public function convertFromHexToAnsiColorCode(string $hexColor): string
{
$hexColor = str_replace('#', '', $hexColor);
if (3 === \strlen($hexColor)) {
$hexColor = $hexColor[0].$hexColor[0].$hexColor[1].$hexColor[1].$hexColor[2].$hexColor[2];
}
if (6 !== \strlen($hexColor)) {
throw new InvalidArgumentException(sprintf('Invalid "#%s" color.', $hexColor));
}
$color = hexdec($hexColor);
$r = ($color >> 16) & 255;
$g = ($color >> 8) & 255;
$b = $color & 255;
return match ($this) {
self::Ansi4 => (string) $this->convertFromRGB($r, $g, $b),
self::Ansi8 => '8;5;'.((string) $this->convertFromRGB($r, $g, $b)),
self::Ansi24 => sprintf('8;2;%d;%d;%d', $r, $g, $b)
};
}
private function convertFromRGB(int $r, int $g, int $b): int
{
return match ($this) {
self::Ansi4 => $this->degradeHexColorToAnsi4($r, $g, $b),
self::Ansi8 => $this->degradeHexColorToAnsi8($r, $g, $b),
default => throw new InvalidArgumentException("RGB cannot be converted to {$this->name}.")
};
}
private function degradeHexColorToAnsi4(int $r, int $g, int $b): int
{
if (0 === round($this->getSaturation($r, $g, $b) / 50)) {
return 0;
}
return (int) ((round($b / 255) << 2) | (round($g / 255) << 1) | round($r / 255));
}
private function getSaturation(int $r, int $g, int $b): int
{
$r = $r / 255;
$g = $g / 255;
$b = $b / 255;
$v = max($r, $g, $b);
if (0 === $diff = $v - min($r, $g, $b)) {
return 0;
}
return (int) ((int) $diff * 100 / $v);
}
/**
* Inspired from https://github.com/ajalt/colormath/blob/e464e0da1b014976736cf97250063248fc77b8e7/colormath/src/commonMain/kotlin/com/github/ajalt/colormath/model/Ansi256.kt code (MIT license).
*/
private function degradeHexColorToAnsi8(int $r, int $g, int $b): int
{
if ($r === $g && $g === $b) {
if ($r < 8) {
return 16;
}
if ($r > 248) {
return 231;
}
return (int) round(($r - 8) / 247 * 24) + 232;
} else {
return 16 +
(36 * (int) round($r / 255 * 5)) +
(6 * (int) round($g / 255 * 5)) +
(int) round($b / 255 * 5);
}
}
}

View File

@@ -16,14 +16,12 @@ namespace Symfony\Component\Console\Output;
*/
class BufferedOutput extends Output
{
private $buffer = '';
private string $buffer = '';
/**
* Empties buffer and returns its content.
*
* @return string
*/
public function fetch()
public function fetch(): string
{
$content = $this->buffer;
$this->buffer = '';
@@ -31,9 +29,6 @@ class BufferedOutput extends Output
return $content;
}
/**
* {@inheritdoc}
*/
protected function doWrite(string $message, bool $newline)
{
$this->buffer .= $message;

View File

@@ -29,8 +29,8 @@ use Symfony\Component\Console\Formatter\OutputFormatterInterface;
*/
class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
{
private $stderr;
private $consoleSectionOutputs = [];
private OutputInterface $stderr;
private array $consoleSectionOutputs = [];
/**
* @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)
@@ -64,44 +64,29 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter());
}
/**
* {@inheritdoc}
*/
public function setDecorated(bool $decorated)
{
parent::setDecorated($decorated);
$this->stderr->setDecorated($decorated);
}
/**
* {@inheritdoc}
*/
public function setFormatter(OutputFormatterInterface $formatter)
{
parent::setFormatter($formatter);
$this->stderr->setFormatter($formatter);
}
/**
* {@inheritdoc}
*/
public function setVerbosity(int $level)
{
parent::setVerbosity($level);
$this->stderr->setVerbosity($level);
}
/**
* {@inheritdoc}
*/
public function getErrorOutput()
public function getErrorOutput(): OutputInterface
{
return $this->stderr;
}
/**
* {@inheritdoc}
*/
public function setErrorOutput(OutputInterface $error)
{
$this->stderr = $error;
@@ -110,10 +95,8 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
/**
* Returns true if current environment supports writing console output to
* STDOUT.
*
* @return bool
*/
protected function hasStdoutSupport()
protected function hasStdoutSupport(): bool
{
return false === $this->isRunningOS400();
}
@@ -121,10 +104,8 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
/**
* Returns true if current environment supports writing console output to
* STDERR.
*
* @return bool
*/
protected function hasStderrSupport()
protected function hasStderrSupport(): bool
{
return false === $this->isRunningOS400();
}

View File

@@ -21,10 +21,8 @@ interface ConsoleOutputInterface extends OutputInterface
{
/**
* Gets the OutputInterface for errors.
*
* @return OutputInterface
*/
public function getErrorOutput();
public function getErrorOutput(): OutputInterface;
public function setErrorOutput(OutputInterface $error);

View File

@@ -21,10 +21,11 @@ use Symfony\Component\Console\Terminal;
*/
class ConsoleSectionOutput extends StreamOutput
{
private $content = [];
private $lines = 0;
private $sections;
private $terminal;
private array $content = [];
private int $lines = 0;
private array $sections;
private Terminal $terminal;
private int $maxHeight = 0;
/**
* @param resource $stream
@@ -38,6 +39,23 @@ class ConsoleSectionOutput extends StreamOutput
$this->terminal = new Terminal();
}
/**
* Defines a maximum number of lines for this section.
*
* When more lines are added, the section will automatically scroll to the
* end (i.e. remove the first lines to comply with the max height).
*/
public function setMaxHeight(int $maxHeight): void
{
// when changing max height, clear output of current section and redraw again with the new height
$existingContent = $this->popStreamContentUntilCurrentSection($this->maxHeight ? min($this->maxHeight, $this->lines) : $this->lines);
$this->maxHeight = $maxHeight;
parent::doWrite($this->getVisibleContent(), false);
parent::doWrite($existingContent, false);
}
/**
* Clears previous output for this section.
*
@@ -50,7 +68,7 @@ class ConsoleSectionOutput extends StreamOutput
}
if ($lines) {
array_splice($this->content, -($lines * 2)); // Multiply lines by 2 to cater for each new line added between content
array_splice($this->content, -$lines);
} else {
$lines = $this->lines;
$this->content = [];
@@ -58,15 +76,13 @@ class ConsoleSectionOutput extends StreamOutput
$this->lines -= $lines;
parent::doWrite($this->popStreamContentUntilCurrentSection($lines), false);
parent::doWrite($this->popStreamContentUntilCurrentSection($this->maxHeight ? min($this->maxHeight, $lines) : $lines), false);
}
/**
* Overwrites the previous output with a new message.
*
* @param array|string $message
*/
public function overwrite($message)
public function overwrite(string|iterable $message)
{
$this->clear();
$this->writeln($message);
@@ -77,21 +93,62 @@ class ConsoleSectionOutput extends StreamOutput
return implode('', $this->content);
}
/**
* @internal
*/
public function addContent(string $input)
public function getVisibleContent(): string
{
foreach (explode(\PHP_EOL, $input) as $lineContent) {
$this->lines += ceil($this->getDisplayLength($lineContent) / $this->terminal->getWidth()) ?: 1;
$this->content[] = $lineContent;
$this->content[] = \PHP_EOL;
if (0 === $this->maxHeight) {
return $this->getContent();
}
return implode('', \array_slice($this->content, -$this->maxHeight));
}
/**
* {@inheritdoc}
* @internal
*/
public function addContent(string $input, bool $newline = true): int
{
$width = $this->terminal->getWidth();
$lines = explode(\PHP_EOL, $input);
$linesAdded = 0;
$count = \count($lines) - 1;
foreach ($lines as $i => $lineContent) {
// re-add the line break (that has been removed in the above `explode()` for
// - every line that is not the last line
// - if $newline is required, also add it to the last line
if ($i < $count || $newline) {
$lineContent .= \PHP_EOL;
}
// skip line if there is no text (or newline for that matter)
if ('' === $lineContent) {
continue;
}
// For the first line, check if the previous line (last entry of `$this->content`)
// needs to be continued (i.e. does not end with a line break).
if (0 === $i
&& (false !== $lastLine = end($this->content))
&& !str_ends_with($lastLine, \PHP_EOL)
) {
// deduct the line count of the previous line
$this->lines -= (int) ceil($this->getDisplayLength($lastLine) / $width) ?: 1;
// concatenate previous and new line
$lineContent = $lastLine.$lineContent;
// replace last entry of `$this->content` with the new expanded line
array_splice($this->content, -1, 1, $lineContent);
} else {
// otherwise just add the new content
$this->content[] = $lineContent;
}
$linesAdded += (int) ceil($this->getDisplayLength($lineContent) / $width) ?: 1;
}
$this->lines += $linesAdded;
return $linesAdded;
}
protected function doWrite(string $message, bool $newline)
{
if (!$this->isDecorated()) {
@@ -100,11 +157,28 @@ class ConsoleSectionOutput extends StreamOutput
return;
}
$erasedContent = $this->popStreamContentUntilCurrentSection();
// Check if the previous line (last entry of `$this->content`) needs to be continued
// (i.e. does not end with a line break). In which case, it needs to be erased first.
$linesToClear = $deleteLastLine = ($lastLine = end($this->content) ?: '') && !str_ends_with($lastLine, \PHP_EOL) ? 1 : 0;
$this->addContent($message);
$linesAdded = $this->addContent($message, $newline);
parent::doWrite($message, true);
if ($lineOverflow = $this->maxHeight > 0 && $this->lines > $this->maxHeight) {
// on overflow, clear the whole section and redraw again (to remove the first lines)
$linesToClear = $this->maxHeight;
}
$erasedContent = $this->popStreamContentUntilCurrentSection($linesToClear);
if ($lineOverflow) {
// redraw existing lines of the section
$previousLinesOfSection = \array_slice($this->content, $this->lines - $this->maxHeight, $this->maxHeight - $linesAdded);
parent::doWrite(implode('', $previousLinesOfSection), false);
}
// if the last line was removed, re-print its content together with the new content.
// otherwise, just print the new content.
parent::doWrite($deleteLastLine ? $lastLine.$message : $message, true);
parent::doWrite($erasedContent, false);
}
@@ -123,7 +197,12 @@ class ConsoleSectionOutput extends StreamOutput
}
$numberOfLinesToClear += $section->lines;
$erasedContent[] = $section->getContent();
if ('' !== $sectionContent = $section->getVisibleContent()) {
if (!str_ends_with($sectionContent, \PHP_EOL)) {
$sectionContent .= \PHP_EOL;
}
$erasedContent[] = $sectionContent;
}
}
if ($numberOfLinesToClear > 0) {

View File

@@ -24,104 +24,65 @@ use Symfony\Component\Console\Formatter\OutputFormatterInterface;
*/
class NullOutput implements OutputInterface
{
private $formatter;
private NullOutputFormatter $formatter;
/**
* {@inheritdoc}
*/
public function setFormatter(OutputFormatterInterface $formatter)
{
// do nothing
}
/**
* {@inheritdoc}
*/
public function getFormatter()
public function getFormatter(): OutputFormatterInterface
{
if ($this->formatter) {
return $this->formatter;
}
// to comply with the interface we must return a OutputFormatterInterface
return $this->formatter = new NullOutputFormatter();
return $this->formatter ??= new NullOutputFormatter();
}
/**
* {@inheritdoc}
*/
public function setDecorated(bool $decorated)
{
// do nothing
}
/**
* {@inheritdoc}
*/
public function isDecorated()
public function isDecorated(): bool
{
return false;
}
/**
* {@inheritdoc}
*/
public function setVerbosity(int $level)
{
// do nothing
}
/**
* {@inheritdoc}
*/
public function getVerbosity()
public function getVerbosity(): int
{
return self::VERBOSITY_QUIET;
}
/**
* {@inheritdoc}
*/
public function isQuiet()
public function isQuiet(): bool
{
return true;
}
/**
* {@inheritdoc}
*/
public function isVerbose()
public function isVerbose(): bool
{
return false;
}
/**
* {@inheritdoc}
*/
public function isVeryVerbose()
public function isVeryVerbose(): bool
{
return false;
}
/**
* {@inheritdoc}
*/
public function isDebug()
public function isDebug(): bool
{
return false;
}
/**
* {@inheritdoc}
*/
public function writeln($messages, int $options = self::OUTPUT_NORMAL)
public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL)
{
// do nothing
}
/**
* {@inheritdoc}
*/
public function write($messages, bool $newline = false, int $options = self::OUTPUT_NORMAL)
public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL)
{
// do nothing
}

View File

@@ -29,8 +29,8 @@ use Symfony\Component\Console\Formatter\OutputFormatterInterface;
*/
abstract class Output implements OutputInterface
{
private $verbosity;
private $formatter;
private int $verbosity;
private OutputFormatterInterface $formatter;
/**
* @param int|null $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)
@@ -44,98 +44,62 @@ abstract class Output implements OutputInterface
$this->formatter->setDecorated($decorated);
}
/**
* {@inheritdoc}
*/
public function setFormatter(OutputFormatterInterface $formatter)
{
$this->formatter = $formatter;
}
/**
* {@inheritdoc}
*/
public function getFormatter()
public function getFormatter(): OutputFormatterInterface
{
return $this->formatter;
}
/**
* {@inheritdoc}
*/
public function setDecorated(bool $decorated)
{
$this->formatter->setDecorated($decorated);
}
/**
* {@inheritdoc}
*/
public function isDecorated()
public function isDecorated(): bool
{
return $this->formatter->isDecorated();
}
/**
* {@inheritdoc}
*/
public function setVerbosity(int $level)
{
$this->verbosity = $level;
}
/**
* {@inheritdoc}
*/
public function getVerbosity()
public function getVerbosity(): int
{
return $this->verbosity;
}
/**
* {@inheritdoc}
*/
public function isQuiet()
public function isQuiet(): bool
{
return self::VERBOSITY_QUIET === $this->verbosity;
}
/**
* {@inheritdoc}
*/
public function isVerbose()
public function isVerbose(): bool
{
return self::VERBOSITY_VERBOSE <= $this->verbosity;
}
/**
* {@inheritdoc}
*/
public function isVeryVerbose()
public function isVeryVerbose(): bool
{
return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;
}
/**
* {@inheritdoc}
*/
public function isDebug()
public function isDebug(): bool
{
return self::VERBOSITY_DEBUG <= $this->verbosity;
}
/**
* {@inheritdoc}
*/
public function writeln($messages, int $options = self::OUTPUT_NORMAL)
public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL)
{
$this->write($messages, true, $options);
}
/**
* {@inheritdoc}
*/
public function write($messages, bool $newline = false, int $options = self::OUTPUT_NORMAL)
public function write(string|iterable $messages, bool $newline = false, int $options = self::OUTPUT_NORMAL)
{
if (!is_iterable($messages)) {
$messages = [$messages];

View File

@@ -33,19 +33,19 @@ interface OutputInterface
/**
* Writes a message to the output.
*
* @param string|iterable $messages The message as an iterable of strings or a single string
* @param bool $newline Whether to add a newline
* @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
* @param bool $newline Whether to add a newline
* @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants),
* 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
*/
public function write($messages, bool $newline = false, int $options = 0);
public function write(string|iterable $messages, bool $newline = false, int $options = 0);
/**
* Writes a message to the output and adds a newline at the end.
*
* @param string|iterable $messages The message as an iterable of strings or a single string
* @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
* @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants),
* 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
*/
public function writeln($messages, int $options = 0);
public function writeln(string|iterable $messages, int $options = 0);
/**
* Sets the verbosity of the output.
@@ -54,38 +54,28 @@ interface OutputInterface
/**
* Gets the current verbosity of the output.
*
* @return int
*/
public function getVerbosity();
public function getVerbosity(): int;
/**
* Returns whether verbosity is quiet (-q).
*
* @return bool
*/
public function isQuiet();
public function isQuiet(): bool;
/**
* Returns whether verbosity is verbose (-v).
*
* @return bool
*/
public function isVerbose();
public function isVerbose(): bool;
/**
* Returns whether verbosity is very verbose (-vv).
*
* @return bool
*/
public function isVeryVerbose();
public function isVeryVerbose(): bool;
/**
* Returns whether verbosity is debug (-vvv).
*
* @return bool
*/
public function isDebug();
public function isDebug(): bool;
/**
* Sets the decorated flag.
@@ -94,17 +84,13 @@ interface OutputInterface
/**
* Gets the decorated flag.
*
* @return bool
*/
public function isDecorated();
public function isDecorated(): bool;
public function setFormatter(OutputFormatterInterface $formatter);
/**
* Returns current output formatter instance.
*
* @return OutputFormatterInterface
*/
public function getFormatter();
public function getFormatter(): OutputFormatterInterface;
}

View File

@@ -47,9 +47,7 @@ class StreamOutput extends Output
$this->stream = $stream;
if (null === $decorated) {
$decorated = $this->hasColorSupport();
}
$decorated ??= $this->hasColorSupport();
parent::__construct($verbosity, $decorated, $formatter);
}
@@ -64,9 +62,6 @@ class StreamOutput extends Output
return $this->stream;
}
/**
* {@inheritdoc}
*/
protected function doWrite(string $message, bool $newline)
{
if ($newline) {
@@ -91,7 +86,7 @@ class StreamOutput extends Output
*
* @return bool true if the stream supports colorization, false otherwise
*/
protected function hasColorSupport()
protected function hasColorSupport(): bool
{
// Follow https://no-color.org/
if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) {

View File

@@ -21,8 +21,8 @@ use Symfony\Component\Console\Formatter\OutputFormatterInterface;
*/
class TrimmedBufferOutput extends Output
{
private $maxLength;
private $buffer = '';
private int $maxLength;
private string $buffer = '';
public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null)
{
@@ -36,10 +36,8 @@ class TrimmedBufferOutput extends Output
/**
* Empties buffer and returns its content.
*
* @return string
*/
public function fetch()
public function fetch(): string
{
$content = $this->buffer;
$this->buffer = '';
@@ -47,9 +45,6 @@ class TrimmedBufferOutput extends Output
return $content;
}
/**
* {@inheritdoc}
*/
protected function doWrite(string $message, bool $newline)
{
$this->buffer .= $message;