diff --git a/danmaku/console-writer/composer.json b/danmaku/console-writer/composer.json deleted file mode 100644 index 3603829..0000000 --- a/danmaku/console-writer/composer.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "danmaku/console-writer", - "type": "library", - "description": "Easily adaptable console input/output writer for Symfony.", - "authors": [ - { - "name": "Marvin Schreurs", - "email": "fristi@danmaku.moe", - "homepage": "https://fristi.danmaku.moe", - "role": "Developer" - } - ], - "support": { - "email": "fristi@danmaku.moe" - }, - "keywords": [ - "console", - "symfony" - ], - "license": "MIT", - "minimum-stability": "dev", - "require": { - "php": ">=7.2.0", - "symfony/console": "^4.2" - }, - "autoload": { - "psr-4": { - "Danmaku\\Console\\": "src/Console" - } - } -} diff --git a/danmaku/console-writer/src/Console/Helper/InheritableQuestionHelper.php b/danmaku/console-writer/src/Console/Helper/InheritableQuestionHelper.php deleted file mode 100644 index 9cb4a87..0000000 --- a/danmaku/console-writer/src/Console/Helper/InheritableQuestionHelper.php +++ /dev/null @@ -1,485 +0,0 @@ - - */ - -namespace Danmaku\Console\Helper; - - -use Symfony\Component\Console\Exception\RuntimeException; -use Symfony\Component\Console\Formatter\OutputFormatter; -use Symfony\Component\Console\Formatter\OutputFormatterStyle; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\StreamableInputInterface; -use Symfony\Component\Console\Output\ConsoleOutputInterface; -use Symfony\Component\Console\Output\ConsoleSectionOutput; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Question\ChoiceQuestion; -use Symfony\Component\Console\Question\Question; - -/** - * Class InheritableQuestionHelper - * - * @package Danmaku\Console\Helper - * @author Marvin Schreurs - */ -class InheritableQuestionHelper extends \Symfony\Component\Console\Helper\QuestionHelper -{ - protected $inputStream; - protected static $shell; - protected static $stty; - - /** - * Asks a question to the user. - * - * @return mixed The user answer - * - * @throws RuntimeException If there is no data to read in the input stream - * @throws \Exception - */ - public function ask(InputInterface $input, OutputInterface $output, Question $question) - { - if ($output instanceof ConsoleOutputInterface) { - $output = $output->getErrorOutput(); - } - - if (!$input->isInteractive()) { - $default = $question->getDefault(); - - if (null === $default) { - return $default; - } - - if ($validator = $question->getValidator()) { - return \call_user_func($question->getValidator(), $default); - } elseif ($question instanceof ChoiceQuestion) { - $choices = $question->getChoices(); - - if (!$question->isMultiselect()) { - return isset($choices[$default]) ? $choices[$default] : $default; - } - - $default = explode(',', $default); - foreach ($default as $k => $v) { - $v = trim($v); - $default[$k] = isset($choices[$v]) ? $choices[$v] : $v; - } - } - - return $default; - } - - if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) { - $this->inputStream = $stream; - } - - if (!$question->getValidator()) { - return $this->doAsk($output, $question); - } - - $interviewer = function () use ($output, $question) { - return $this->doAsk($output, $question); - }; - - return $this->validateAttempts($interviewer, $output, $question); - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return 'question'; - } - - /** - * Prevents usage of stty. - */ - public static function disableStty() - { - static::$stty = false; - } - - /** - * Asks the question to the user. - * - * @return bool|mixed|string|null - * - * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden - */ - protected function doAsk(OutputInterface $output, Question $question) - { - $this->writePrompt($output, $question); - - $inputStream = $this->inputStream ?: STDIN; - $autocomplete = $question->getAutocompleterCallback(); - - if (null === $autocomplete || !$this->hasSttyAvailable()) { - $ret = false; - if ($question->isHidden()) { - try { - $ret = trim($this->getHiddenResponse($output, $inputStream)); - } catch (RuntimeException $e) { - if (!$question->isHiddenFallback()) { - throw $e; - } - } - } - - if (false === $ret) { - $ret = fgets($inputStream, 4096); - if (false === $ret) { - throw new RuntimeException('Aborted.'); - } - $ret = trim($ret); - } - } else { - $ret = trim($this->autocomplete($output, $question, $inputStream, $autocomplete)); - } - - if ($output instanceof ConsoleSectionOutput) { - $output->addContent($ret); - } - - $ret = \strlen($ret) > 0 ? $ret : $question->getDefault(); - - if ($normalizer = $question->getNormalizer()) { - return $normalizer($ret); - } - - return $ret; - } - - /** - * Outputs the question prompt. - */ - protected function writePrompt(OutputInterface $output, Question $question) - { - $message = $question->getQuestion(); - - if ($question instanceof ChoiceQuestion) { - $maxWidth = max(array_map([$this, 'strlen'], array_keys($question->getChoices()))); - - $messages = (array) $question->getQuestion(); - foreach ($question->getChoices() as $key => $value) { - $width = $maxWidth - $this->strlen($key); - $messages[] = ' ['.$key.str_repeat(' ', $width).'] '.$value; - } - - $output->writeln($messages); - - $message = $question->getPrompt(); - } - - $output->write($message); - } - - /** - * Outputs an error message. - */ - protected function writeError(OutputInterface $output, \Exception $error) - { - if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) { - $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'); - } else { - $message = ''.$error->getMessage().''; - } - - $output->writeln($message); - } - - /** - * Autocompletes a question. - * - * @param resource $inputStream - * @return string - */ - private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete): string - { - $fullChoice = ''; - $ret = ''; - - $i = 0; - $ofs = -1; - $matches = $autocomplete($ret); - $numMatches = \count($matches); - - $sttyMode = shell_exec('stty -g'); - - // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead) - shell_exec('stty -icanon -echo'); - - // Add highlighted text style - $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white')); - - // Read a keypress - while (!feof($inputStream)) { - $c = fread($inputStream, 1); - - // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false. - if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) { - shell_exec(sprintf('stty %s', $sttyMode)); - throw new RuntimeException('Aborted.'); - } elseif ("\177" === $c) { // Backspace Character - if (0 === $numMatches && 0 !== $i) { - --$i; - $fullChoice = substr($fullChoice, 0, -1); - // Move cursor backwards - $output->write("\033[1D"); - } - - if (0 === $i) { - $ofs = -1; - $matches = $autocomplete($ret); - $numMatches = \count($matches); - } else { - $numMatches = 0; - } - - // Pop the last character off the end of our string - $ret = substr($ret, 0, $i); - } elseif ("\033" === $c) { - // Did we read an escape sequence? - $c .= fread($inputStream, 2); - - // A = Up Arrow. B = Down Arrow - if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) { - if ('A' === $c[2] && -1 === $ofs) { - $ofs = 0; - } - - if (0 === $numMatches) { - continue; - } - - $ofs += ('A' === $c[2]) ? -1 : 1; - $ofs = ($numMatches + $ofs) % $numMatches; - } - } elseif (\ord($c) < 32) { - if ("\t" === $c || "\n" === $c) { - if ($numMatches > 0 && -1 !== $ofs) { - $ret = (string) $matches[$ofs]; - // Echo out remaining chars for current match - $remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)))); - $output->write($remainingCharacters); - $fullChoice .= $remainingCharacters; - $i = \strlen($fullChoice); - - $matches = array_filter( - $autocomplete($ret), - function ($match) use ($ret) { - return '' === $ret || 0 === strpos($match, $ret); - } - ); - $numMatches = \count($matches); - $ofs = -1; - } - - if ("\n" === $c) { - $output->write($c); - break; - } - } - - continue; - } else { - if ("\x80" <= $c) { - $c .= fread($inputStream, ["\xC0" => 1, "\xD0" => 1, "\xE0" => 2, "\xF0" => 3][$c & "\xF0"]); - } - - $output->write($c); - $ret .= $c; - $fullChoice .= $c; - ++$i; - - $tempRet = $ret; - - if ($question instanceof ChoiceQuestion && $question->isMultiselect()) { - $tempRet = $this->mostRecentlyEnteredValue($fullChoice); - } - - $numMatches = 0; - $ofs = 0; - - foreach ($autocomplete($ret) as $value) { - // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) - if (0 === strpos($value, $tempRet)) { - $matches[$numMatches++] = $value; - } - } - } - - // Erase characters from cursor to end of line - $output->write("\033[K"); - - if ($numMatches > 0 && -1 !== $ofs) { - // Save cursor position - $output->write("\0337"); - // Write highlighted text, complete the partially entered response - $charactersEntered = \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))); - $output->write(''.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $charactersEntered)).''); - // Restore cursor position - $output->write("\0338"); - } - } - - // Reset stty so it behaves normally again - shell_exec(sprintf('stty %s', $sttyMode)); - - return $fullChoice; - } - - private function mostRecentlyEnteredValue($entered) - { - // Determine the most recent value that the user entered - if (false === strpos($entered, ',')) { - return $entered; - } - - $choices = explode(',', $entered); - if (\strlen($lastChoice = trim($choices[\count($choices) - 1])) > 0) { - return $lastChoice; - } - - return $entered; - } - - /** - * Gets a hidden response from user. - * - * @param OutputInterface $output An Output instance - * @param resource $inputStream The handler resource - * - * @return string - * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden - */ - private function getHiddenResponse(OutputInterface $output, $inputStream): string - { - if ('\\' === \DIRECTORY_SEPARATOR) { - $exe = __DIR__.'/../Resources/bin/hiddeninput.exe'; - - // handle code running from a phar - if ('phar:' === substr(__FILE__, 0, 5)) { - $tmpExe = sys_get_temp_dir().'/hiddeninput.exe'; - copy($exe, $tmpExe); - $exe = $tmpExe; - } - - $value = rtrim(shell_exec($exe)); - $output->writeln(''); - - if (isset($tmpExe)) { - unlink($tmpExe); - } - - return $value; - } - - if ($this->hasSttyAvailable()) { - $sttyMode = shell_exec('stty -g'); - - shell_exec('stty -echo'); - $value = fgets($inputStream, 4096); - shell_exec(sprintf('stty %s', $sttyMode)); - - if (false === $value) { - throw new RuntimeException('Aborted.'); - } - - $value = trim($value); - $output->writeln(''); - - return $value; - } - - if (false !== $shell = $this->getShell()) { - $readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword'; - $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd); - $value = rtrim(shell_exec($command)); - $output->writeln(''); - - return $value; - } - - throw new RuntimeException('Unable to hide the response.'); - } - - /** - * Validates an attempt. - * - * @param callable $interviewer A callable that will ask for a question and return the result - * @param OutputInterface $output An Output instance - * @param Question $question A Question instance - * - * @return mixed The validated response - * - * @throws \Exception In case the max number of attempts has been reached and no valid response has been given - */ - protected function validateAttempts(callable $interviewer, OutputInterface $output, Question $question) - { - $error = null; - $attempts = $question->getMaxAttempts(); - while (null === $attempts || $attempts--) { - if (null !== $error) { - $this->writeError($output, $error); - } - - try { - return $question->getValidator()($interviewer()); - } catch (RuntimeException $e) { - throw $e; - } catch (\Exception $error) { - } - } - - throw $error; - } - - /** - * Returns a valid unix shell. - * - * @return string|bool The valid shell name, false in case no valid shell is found - */ - protected function getShell() - { - if (null !== static::$shell) { - return static::$shell; - } - - static::$shell = false; - - if (file_exists('/usr/bin/env')) { - // handle other OSs with bash/zsh/ksh/csh if available to hide the answer - $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null"; - foreach (['bash', 'zsh', 'ksh', 'csh'] as $sh) { - if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) { - static::$shell = $sh; - break; - } - } - } - - return static::$shell; - } - - /** - * Returns whether Stty is available or not. - */ - protected function hasSttyAvailable(): bool - { - if (null !== static::$stty) { - return static::$stty; - } - - exec('stty 2>&1', $output, $exitcode); - - return static::$stty = 0 === $exitcode; - } -} \ No newline at end of file diff --git a/danmaku/console-writer/src/Console/Helper/QuestionHelper.php b/danmaku/console-writer/src/Console/Helper/QuestionHelper.php deleted file mode 100644 index d94b5d1..0000000 --- a/danmaku/console-writer/src/Console/Helper/QuestionHelper.php +++ /dev/null @@ -1,149 +0,0 @@ - - */ - -namespace Danmaku\Console\Helper; - - -use Symfony\Component\Console\Exception\RuntimeException; -use Symfony\Component\Console\Formatter\OutputFormatter; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\StreamableInputInterface; -use Symfony\Component\Console\Output\ConsoleOutputInterface; -use Symfony\Component\Console\Output\ConsoleSectionOutput; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Question\ChoiceQuestion; -use Symfony\Component\Console\Question\ConfirmationQuestion; -use Symfony\Component\Console\Question\Question; -use Symfony\Component\Console\Style\SymfonyStyle; - -/** - * Class QuestionHelper - * - * @package Danmaku\Console\Helper - * @author Marvin Schreurs - */ -class QuestionHelper extends InheritableQuestionHelper -{ - public function ask(InputInterface $input, OutputInterface $output, Question $question) - { - if ($output instanceof ConsoleOutputInterface) { - $output = $output->getErrorOutput(); - } - - if (!$input->isInteractive()) { - $default = $question->getDefault(); - - if (null === $default) { - return $default; - } - - if ($validator = $question->getValidator()) { - return \call_user_func($question->getValidator(), $default); - } elseif ($question instanceof ChoiceQuestion) { - if (!$question->isMultiselect()) { - return $default; - } - - $default = explode(',', $default); - foreach ($default as $k => $v) { - $v = trim($v); - $default[$k] = $v; - } - } - - return $default; - } - - if ($input instanceof StreamableInputInterface && $stream = $input->getStream()) { - $this->inputStream = $stream; - } - - if (!$question->getValidator()) { - return $this->doAsk($output, $question); - } - - $interviewer = function () use ($output, $question) { - return $this->doAsk($output, $question); - }; - - return $this->validateAttempts($interviewer, $output, $question); - } - - /** - * {@inheritdoc} - */ - protected function writePrompt(OutputInterface $output, Question $question) - { - $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion()); - $default = $question->getDefault(); - - switch (true) { - case null === $default: - $text = sprintf(' %s:', $text); - - break; - - case $question instanceof ConfirmationQuestion: - $text = sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); - - break; - - case $question instanceof ChoiceQuestion && $question->isMultiselect(): - $choices = $question->getChoices(); - $default = explode(',', $default); - - foreach ($default as $key => $value) { - $default[$key] = $choices[trim($value)]; - } - - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); - - break; - - case $question instanceof ChoiceQuestion: - $choices = $question->getChoices(); - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape(isset($choices[$default]) ? $choices[$default] : $default)); - - break; - - default: - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); - } - - $output->writeln($text); - - if ($question instanceof ChoiceQuestion) { - $width = max(array_map('strlen', array_keys($question->getChoices()))); - - foreach ($question->getChoices() as $key => $value) { - $output->writeln(sprintf(" [%-${width}s] %s", $key, $value)); - } - } - - $output->write(' > '); - } - - /** - * {@inheritdoc} - */ - protected function writeError(OutputInterface $output, \Exception $error) - { - if ($output instanceof SymfonyStyle) { - $output->newLine(); - $output->error($error->getMessage()); - - return; - } - - parent::writeError($output, $error); - } -} \ No newline at end of file diff --git a/danmaku/console-writer/src/Console/Question/ChoiceQuestion.php b/danmaku/console-writer/src/Console/Question/ChoiceQuestion.php deleted file mode 100644 index 05ce56d..0000000 --- a/danmaku/console-writer/src/Console/Question/ChoiceQuestion.php +++ /dev/null @@ -1,31 +0,0 @@ - - */ - -namespace Danmaku\Console\Question; - - -use Symfony\Component\Console\Exception\InvalidArgumentException; -use Symfony\Component\Console\Question\ChoiceQuestion as SymfonyChoiceQuestion; - -/** - * Class ChoiceQuestion - * - * @package Danmaku\Console\Question - * @author Marvin Schreurs - */ -class ChoiceQuestion extends SymfonyChoiceQuestion -{ - protected function isAssoc($array) - { - return true; - } -} \ No newline at end of file diff --git a/danmaku/console-writer/src/Console/Question/ConfirmationQuestion.php b/danmaku/console-writer/src/Console/Question/ConfirmationQuestion.php deleted file mode 100644 index f333517..0000000 --- a/danmaku/console-writer/src/Console/Question/ConfirmationQuestion.php +++ /dev/null @@ -1,30 +0,0 @@ - - */ - -namespace Danmaku\Console\Question; - - -use Symfony\Component\Console\Question\ConfirmationQuestion as SymfonyConfirmationQuestion; - -/** - * Class ConfirmationQuestion - * - * @package Danmaku\Console\Question - * @author Marvin Schreurs - */ -class ConfirmationQuestion extends SymfonyConfirmationQuestion -{ - protected function isAssoc($array) - { - return true; - } -} \ No newline at end of file diff --git a/danmaku/console-writer/src/Console/Question/Question.php b/danmaku/console-writer/src/Console/Question/Question.php deleted file mode 100644 index 2354590..0000000 --- a/danmaku/console-writer/src/Console/Question/Question.php +++ /dev/null @@ -1,30 +0,0 @@ - - */ - -namespace Danmaku\Console\Question; - - -use Symfony\Component\Console\Question\Question as SymfonyQuestion; - -/** - * Class Question - * - * @package Danmaku\Console\Question - * @author Marvin Schreurs - */ -class Question extends SymfonyQuestion -{ - protected function isAssoc($array) - { - return true; - } -} \ No newline at end of file diff --git a/danmaku/console-writer/src/Console/Writer/DefaultOutputWriter.php b/danmaku/console-writer/src/Console/Writer/DefaultOutputWriter.php deleted file mode 100644 index e3706ea..0000000 --- a/danmaku/console-writer/src/Console/Writer/DefaultOutputWriter.php +++ /dev/null @@ -1,546 +0,0 @@ - - */ - -namespace Danmaku\Console\Writer; - - -use Danmaku\LaravelConsoleWriter\Console\Helper\QuestionHelper; -use Danmaku\LaravelConsoleWriter\Console\Question\ChoiceQuestion; -use Danmaku\LaravelConsoleWriter\Console\Question\ConfirmationQuestion; -use Danmaku\LaravelConsoleWriter\Console\Question\Question; -use Symfony\Component\Console\Exception\RuntimeException; -use Symfony\Component\Console\Formatter\OutputFormatter; -use Symfony\Component\Console\Formatter\OutputFormatterStyle; -use Symfony\Component\Console\Helper\Helper; -use Symfony\Component\Console\Helper\ProgressBar; -use Symfony\Component\Console\Helper\SymfonyQuestionHelper; -use Symfony\Component\Console\Helper\Table; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\BufferedOutput; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Question\Question as SymfonyQuestion; -use Symfony\Component\Console\Terminal; - -/** - * Class DefaultOutputWriter - * - * @package Danmaku\Console\Writer - * @author Marvin Schreurs - */ -class DefaultOutputWriter implements OutputWriterInterface -{ - /** - * Console input interface. - * - * @var InputInterface $input - */ - protected $input; - - /** - * Console output interface. - * - * @var OutputInterface $output - */ - protected $output; - - /** - * ProgressBar instance. - * - * @var ProgressBar $progressBar - */ - protected $progressBar; - - /** - * Output buffer. - * - * @var BufferedOutput $bufferedOutput - */ - protected $bufferedOutput; - - /** - * Helper instance for handling questions. - * - * @var SymfonyQuestionHelper $questionHelper - */ - protected $questionHelper; - - /** - * Calculated line length that will be used in the console. - * - * @var int $lineLength - */ - protected $lineLength; - - /** - * The list of available output styles with their settings. - * - * @var array $styles - */ - protected $styles = [ - 'comment' => ['white', 'black'], - 'info' => ['cyan', 'black'], - 'warning' => ['yellow', 'black'], - 'danger' => ['red', 'black'], - 'success' => ['green', 'black'], - 'debug' => ['black', 'white'], - 'comment-bg' => ['black', 'white'], - 'info-bg' => ['black', 'cyan'], - 'warning-bg' => ['black', 'yellow'], - 'danger-bg' => ['white', 'red'], - 'success-bg' => ['black', 'green'], - 'debug-bg' => ['black', 'white'], - 'title' => ['green', 'black'], - 'section' => ['white', 'black'], - 'question'=> ['green', 'black'], - 'answer' => ['yellow', 'black'], - 'choice' => ['yellow', 'black'], - ]; - - /** - * The maximum length of lines to use for console ouput. - * - * @var int $maxLineLength - */ - protected $maxLineLength = 120; - - /** - * BaseOutputStyler constructor. - * - * @param InputInterface $input - * @param OutputInterface $output - */ - public function __construct(InputInterface $input, OutputInterface $output) - { - //Set input and output interface - $this->input = $input; - $this->output = $output; - - //Set additional output styles - foreach($this->styles as $style => $values) { - $formatter = new OutputFormatterStyle($values[0], $values[1]); - $output->getFormatter()->setStyle($style, $formatter); - } - - $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter()); - // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. - $width = (new Terminal())->getWidth() ?: $this->maxLineLength; - $this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), $this->maxLineLength); - } - - public function title(string $title): void - { - $this->autoPrependBlock(); - $this->writeln([ - sprintf('%s</>', OutputFormatter::escapeTrailingBackslash($title)), - sprintf('<title>%s</>', str_repeat('=', Helper::strlenWithoutDecoration($this->output->getFormatter(), $title))), - ]); - $this->newLine(); - } - - public function section(string $heading): void - { - $this->autoPrependBlock(); - $this->writeln([ - sprintf('<section>%s</>', OutputFormatter::escapeTrailingBackslash($heading)), - sprintf('<section>%s</>', str_repeat('-', Helper::strlenWithoutDecoration($this->output->getFormatter(), $heading))), - ]); - $this->newLine(); - } - - public function table(array $headers, array $rows): void - { - $style = clone Table::getStyleDefinition('symfony-style-guide'); - $style->setCellHeaderFormat('<info>%s</info>'); - - $table = new Table($this->output); - $table->setHeaders($headers); - $table->setRows($rows); - $table->setStyle($style); - - $table->render(); - $this->newLine(); - } - - public function list(array $items, bool $dictionary = false): void - { - $this->autoPrependText(); - - if($dictionary) { - $width = $this->_getColumnWidth(array_keys($items)); - $this->newLine(); - foreach($items as $item => $description) { - //Format line - $spacingWidth = $width - Helper::strlen($item); - $line = sprintf(' %s%s%s', $item, str_repeat(' ', $spacingWidth), $description); - $this->writeln($line); - } - } else { - $items = array_map(function ($item) { - return sprintf(' * %s', $item); - }, $items); - $this->writeln($items); - } - - $this->newLine(); - } - - public function text($message, string $style = null, $verbosity = OutputInterface::VERBOSITY_NORMAL): void - { - $this->autoPrependText(); - - $messages = \is_array($message) ? array_values($message) : [$message]; - foreach ($messages as $message) { - if(!empty($style)){ - $message = sprintf(" <$style>%s</>", $message); - } - - $this->writeln(sprintf(' %s', $message), $verbosity); - } - } - - public function success($message, bool $padding = false): void - { - if(!$this->output->isQuiet()) { - $style = $padding ? 'success-bg' : 'success'; - $this->block($message, 'OK', $style, ' ', $padding); - } - } - - public function error($message, bool $padding = false): void - { - if(!$this->output->isQuiet()) { - $style = $padding ? 'danger-bg' : 'danger'; - $this->block($message, 'ERROR', $style, ' ', $padding); - } - } - - public function warning($message, bool $padding = false): void - { - if(!$this->output->isQuiet()) { - $style = $padding ? 'warning-bg' : 'warning'; - $this->block($message, 'WARN', $style, ' ', $padding); - } - } - - public function comment($message, bool $padding = false): void - { - if($this->output->isVeryVerbose()) { - $style = $padding ? 'comment-bg' : 'comment'; - $this->block($message, null, $style, " // ", $padding, false); - } - } - - public function info($message, bool $padding = false): void - { - if($this->output->isVeryVerbose()) { - $style = $padding ? 'info-bg' : 'info'; - $this->block($message, 'INFO', $style, ' ', $padding); - } - } - - public function debug($message, bool $padding = false): void - { - if($this->output->isDebug()) { - $style = $padding ? 'debug-bg' : 'debug'; - $this->block($message, 'DEBUG', $style, ' ', $padding); - } - } - - public function exception(\Throwable $throwable, string $message = null): void - { - $this->error([ - $message ?? 'An exception has occurred!', - sprintf('In %s on line %s:', $throwable->getFile(), $throwable->getLine()), - $throwable->getMessage() - ], true); - } - - public function ask(string $question, $default = null, $validator = null) - { - $question = new Question($question, $default); - $question->setValidator($validator); - - return $this->askQuestion($question); - } - - public function password(string $question, $validator = null) - { - $question = new Question($question); - - $question->setHidden(true); - $question->setValidator($validator); - - return $this->askQuestion($question); - } - - public function confirm(string $question, $default = true): bool - { - return $this->askQuestion(new ConfirmationQuestion($question, $default)); - } - - public function choice(string $question, array $choices, $default = null) - { - return $this->askQuestion(new ChoiceQuestion($question, $choices, $default)); - } - - public function startProgress(int $max = 0): void - { - $this->progressBar = $this->createProgress($max); - $this->progressBar->start(); - } - - public function advanceProgress(int $step = 1): void - { - $this->getProgressBar()->advance($step); - } - - public function finishProgress(): void - { - $this->getProgressBar()->finish(); - $this->newLine(2); - $this->progressBar = null; - } - - public function createProgress(int $max = 0): ProgressBar - { - $progressBar = new ProgressBar($this->output, $max); - - $progressBar->setBarCharacter('<success>=</>'); - $progressBar->setEmptyBarCharacter('<danger> </>'); - $progressBar->setProgressCharacter('<warning>></>'); - $progressBar->setBarWidth(60); - $progressBar->setFormat( - " %status%\n %current%/%max% [%bar%] %percent:3s%%\n 🏁 %estimated:-50s% %memory:20s%" - ); - - return $progressBar; - } - - public function newLine($count = 1): void - { - $this->output->write(str_repeat(PHP_EOL, $count)); - $this->bufferedOutput->write(str_repeat("\n", $count)); - } - - /** - * @param $messages - * @param int $type - */ - protected function writeln($messages, $type = OutputInterface::OUTPUT_NORMAL) - { - if (!is_iterable($messages)) { - $messages = [$messages]; - } - - foreach ($messages as $message) { - $this->output->writeln($message, $type); - $this->writeBuffer($message, true, $type); - } - } - - /** - * @param $messages - * @param bool $newline - * @param int $type - */ - protected function write($messages, $newline = false, $type = OutputInterface::OUTPUT_NORMAL) - { - if (!is_iterable($messages)) { - $messages = [$messages]; - } - - foreach ($messages as $message) { - $this->output->write($message, $newline, $type); - $this->writeBuffer($message, $newline, $type); - } - } - - /** - * @param SymfonyQuestion $question - * @return mixed - * @throws \Exception - */ - protected function askQuestion(SymfonyQuestion $question) - { - if ($this->input->isInteractive()) { - $this->autoPrependBlock(); - } - - if (!$this->questionHelper) { - $this->questionHelper = new QuestionHelper(); - } - - $answer = $this->questionHelper->ask($this->input, $this->output, $question); - - if ($this->input->isInteractive()) { - $this->newLine(); - $this->bufferedOutput->write("\n"); - } - - return $answer; - } - - /** - * Prepend a new line for an upcoming block. - * - * @return void - */ - protected function autoPrependBlock(): void - { - $chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2); - - if (!isset($chars[0])) { - $this->newLine(); //empty history, so we should start with a new line. - - return; - } - //Prepend new line for each non LF chars (This means no blank line was output before) - $this->newLine(2 - substr_count($chars, "\n")); - } - - /** - * Prepend a new line for upcoming text. - * - * @return void - */ - protected function autoPrependText(): void - { - $fetched = $this->bufferedOutput->fetch(); - //Prepend new line if last char isn't EOL: - if ("\n" !== substr($fetched, -1)) { - $this->newLine(); - } - } - - /** - * @param string $message - * @param bool $newLine - * @param int $type - */ - protected function writeBuffer(string $message, bool $newLine, int $type): void - { - // We need to know if the two last chars are PHP_EOL - // Preserve the last 4 chars inserted (PHP_EOL on windows is two chars) in the history buffer - $this->bufferedOutput->write(substr($message, -4), $newLine, $type); - } - - /** - * Formats a message as a block of text. - * - * @param string|array $messages The message to write in the block - * @param string|null $type The block type (added in [] on first line) - * @param string|null $style The style to apply to the whole block - * @param string $prefix The prefix for the block - * @param bool $padding Whether to add vertical padding - * @param bool $escape Whether to escape the message - * @param int $verbosity - */ - protected function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false, $escape = true, $verbosity = OutputInterface::OUTPUT_NORMAL) - { - $messages = \is_array($messages) ? array_values($messages) : [$messages]; - - if($padding) { - $this->autoPrependBlock(); - } else { - $this->autoPrependText(); - } - - $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape), $verbosity); - - if($padding) { - $this->newLine(); - } - } - - /** - * Format a set of messages as a block. - * - * @param iterable $messages - * @param string|null $type - * @param string|null $style - * @param string $prefix - * @param bool $padding - * @param bool $escape - * @return array - */ - private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false) - { - $indentLength = 0; - $prefixLength = Helper::strlenWithoutDecoration($this->output->getFormatter(), $prefix); - $lines = []; - - if (null !== $type) { - $type = sprintf('[%s] ', $type); - $indentLength = \strlen($type); - $lineIndentation = str_repeat(' ', $indentLength); - } - - // wrap and add newlines for each element - foreach ($messages as $key => $message) { - if ($escape) { - $message = OutputFormatter::escape($message); - } - - $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - $prefixLength - $indentLength, PHP_EOL, true))); - - if (\count($messages) > 1 && $key < \count($messages) - 1) { - $lines[] = ''; - } - } - - $firstLineIndex = 0; - if ($padding && $this->output->isDecorated()) { - $firstLineIndex = 1; - array_unshift($lines, ''); - $lines[] = ''; - } - - foreach ($lines as $i => &$line) { - if (null !== $type) { - $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line; - } - - $line = $prefix.$line; - $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->output->getFormatter(), $line)); - - if ($style) { - $line = sprintf('<%s>%s</>', $style, $line); - } - } - - return $lines; - } - - protected function getProgressBar(): ProgressBar - { - if (!$this->progressBar) { - throw new RuntimeException('The ProgressBar is not started.'); - } - - return $this->progressBar; - } - - /** - * Calculate the column width that fits all items. - * - * @param array $items - * @return int - */ - private function _getColumnWidth(array $items): int - { - $widths = []; - foreach ($items as $item) { - $widths[] = Helper::strlen($item); - } - return $widths ? max($widths) + 2 : 0; - } -} \ No newline at end of file diff --git a/danmaku/console-writer/src/Console/Writer/OutputWriterInterface.php b/danmaku/console-writer/src/Console/Writer/OutputWriterInterface.php deleted file mode 100644 index a3ff7c6..0000000 --- a/danmaku/console-writer/src/Console/Writer/OutputWriterInterface.php +++ /dev/null @@ -1,206 +0,0 @@ -<?php -/** - * OutputWriterInterface interface source file. - * - * Contains the source code of the OutputWriterInterface interface. - * - * PHP version 7.2 - * - * @package Danmaku\Console\Writer - * @author Marvin Schreurs <fristi@danmaku.moe> - */ - -namespace Danmaku\Console\Writer; - - -use Symfony\Component\Console\Helper\ProgressBar; -use Symfony\Component\Console\Output\OutputInterface; - -/** - * Interface OutputWriterInterface - * - * @package Danmaku\Console\Writer - * @author Marvin Schreurs <fristi@danmaku.moe> - */ -interface OutputWriterInterface -{ - /** - * Formats a command title. - * - * @param string $title The title text to display. - * @return void - */ - public function title(string $title): void; - - /** - * Formats a command section. - * - * @param string $heading The section heading to display. - * @return void - */ - public function section(string $heading): void; - - /** - * Formats a table. - * - * @param array $headers A list of column headers. - * @param array $rows A list of rows with cells. - * @return void - */ - public function table(array $headers, array $rows): void; - - /** - * Formats a list. - * - * @param array $items A list of items. - * @param bool $dictionary Print the list as key/value pairs. - * @return void - */ - public function list(array $items, bool $dictionary = false): void; - - /** - * Writes an unformatted line of text. - * - * @param string|array $message Message to display. - * @param string|null $style Style to apply to the message. - * @param int $verbosity Verbosity level at which this message should be printed. - * @return void - */ - public function text($message, string $style = null, $verbosity = OutputInterface::VERBOSITY_NORMAL): void; - - /** - * Formats a success message. - * - * @param string|array $message Message to display. - * @param bool $padding Render the message in a padded box. - * @return void - */ - public function success($message, bool $padding = false): void; - - /** - * Formats an error message. - * - * @param string|array $message Message to display. - * @param bool $padding Render the message in a padded box. - * @return void - */ - public function error($message, bool $padding = false): void; - - /** - * Formats a warning message. - * - * @param string|array $message Message to display. - * @param bool $padding Render the message in a padded box. - * @return void - */ - public function warning($message, bool $padding = false): void; - - /** - * Formats a comment message. - * - * @param string|array $message Message to display. - * @param bool $padding Render the message in a padded box. - * @return void - */ - public function comment($message, bool $padding = false): void; - - /** - * Formats an information message. - * - * @param string|array $message Message to display. - * @param bool $padding Render the message in a padded box. - * @return void - */ - public function info($message, bool $padding = false): void; - - /** - * Formats a debug message. - * - * @param string|array $message Message to display. - * @param bool $padding Render the message in a padded box. - * @return void - */ - public function debug($message, bool $padding = false): void; - - /** - * Formats an exception. - * - * @param \Throwable $throwable A throwable instance to report. - * @param string|null $message Message to display with the exception. - * @return void - */ - public function exception(\Throwable $throwable, string $message = null): void; - - /** - * Asks the user for input. - * - * @param string $question Question to display. - * @param mixed|null $default Default value for input. - * @param callable|null $validator Callable used to validate input. - * @return mixed The user's input. - */ - public function ask(string $question, $default = null, $validator = null); - - /** - * Ask the user for input, the input will be hidden. - * - * @param string $question Question to display. - * @param callable|null $validator Callable used to validate input. - * @return mixed The user's input. - */ - public function password(string $question, $validator = null); - - /** - * Ask the user for confirmation (yes or no). - * - * @param string $question Question to display. - * @param bool $default Default value for input. - * @return bool The user's input. - */ - public function confirm(string $question, $default = true): bool; - - /** - * Ask the user for input using a list of choices. - * - * @param string $question Question to display. - * @param array $choices List of choices. - * @param mixed|null $default Default value for input. - * @return mixed The user's input. - */ - public function choice(string $question, array $choices, $default = null); - - /** - * Start a progressbar. - * - * @param int $max Maximum steps (0 if unknown). - */ - public function startProgress(int $max = 0): void; - - /** - * Advance the progressbar by the given number of steps. - * - * @param int $step Amount of steps to advance. - */ - public function advanceProgress(int $step = 1): void; - - /** - * Stop the progressbar. - */ - public function finishProgress(): void; - - /** - * Create a ProgressBar instance. - * - * @param int $max Maximum steps (0 if unknown). - * @return ProgressBar The ProgressBar instance. - */ - public function createProgress(int $max = 0): ProgressBar; - - /** - * Add newlines. - * - * @param int $count - * @return void - */ - public function newLine(int $count = 1): void; -} \ No newline at end of file