From 12d6d21abb85f90105743767366dac62de52fece Mon Sep 17 00:00:00 2001 From: Santiago San Martin Date: Wed, 21 May 2025 23:21:01 -0300 Subject: [PATCH 1/8] [Console][Messenger] Fix: Allow UnrecoverableExceptionInterface to bypass retry in RunCommandMessageHandler Co-authored-by: Kevin Bond --- Messenger/RunCommandMessageHandler.php | 4 ++ .../RunCommandMessageHandlerTest.php | 46 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/Messenger/RunCommandMessageHandler.php b/Messenger/RunCommandMessageHandler.php index 14f9c1764..2d698c734 100644 --- a/Messenger/RunCommandMessageHandler.php +++ b/Messenger/RunCommandMessageHandler.php @@ -16,6 +16,8 @@ use Symfony\Component\Console\Exception\RunCommandFailedException; use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\BufferedOutput; +use Symfony\Component\Messenger\Exception\RecoverableExceptionInterface; +use Symfony\Component\Messenger\Exception\UnrecoverableExceptionInterface; /** * @author Kevin Bond @@ -35,6 +37,8 @@ public function __invoke(RunCommandMessage $message): RunCommandContext try { $exitCode = $this->application->run($input, $output); + } catch (UnrecoverableExceptionInterface|RecoverableExceptionInterface $e) { + throw $e; } catch (\Throwable $e) { throw new RunCommandFailedException($e, new RunCommandContext($message, Command::FAILURE, $output->fetch())); } diff --git a/Tests/Messenger/RunCommandMessageHandlerTest.php b/Tests/Messenger/RunCommandMessageHandlerTest.php index adc31e0ec..3d8e3e195 100644 --- a/Tests/Messenger/RunCommandMessageHandlerTest.php +++ b/Tests/Messenger/RunCommandMessageHandlerTest.php @@ -20,6 +20,10 @@ use Symfony\Component\Console\Messenger\RunCommandMessage; use Symfony\Component\Console\Messenger\RunCommandMessageHandler; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Messenger\Exception\RecoverableExceptionInterface; +use Symfony\Component\Messenger\Exception\RecoverableMessageHandlingException; +use Symfony\Component\Messenger\Exception\UnrecoverableExceptionInterface; +use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; /** * @author Kevin Bond @@ -81,6 +85,38 @@ public function testThrowOnNonSuccess() $this->fail('Exception not thrown.'); } + public function testExecutesCommandThatThrownUnrecoverableException() + { + $handler = new RunCommandMessageHandler($this->createApplicationWithCommand()); + + try { + $handler(new RunCommandMessage('test:command --throw-unrecoverable')); + } catch (UnrecoverableExceptionInterface $e) { + $this->assertSame('Unrecoverable exception message', $e->getMessage()); + $this->assertNull($e->getPrevious()); + + return; + } + + $this->fail('Exception not thrown.'); + } + + public function testExecutesCommandThatThrownRecoverableException() + { + $handler = new RunCommandMessageHandler($this->createApplicationWithCommand()); + + try { + $handler(new RunCommandMessage('test:command --throw-recoverable')); + } catch (RecoverableExceptionInterface $e) { + $this->assertSame('Recoverable exception message', $e->getMessage()); + $this->assertNull($e->getPrevious()); + + return; + } + + $this->fail('Exception not thrown.'); + } + private function createApplicationWithCommand(): Application { $application = new Application(); @@ -92,6 +128,8 @@ public function configure(): void $this ->setName('test:command') ->addOption('throw') + ->addOption('throw-unrecoverable') + ->addOption('throw-recoverable') ->addOption('exit', null, InputOption::VALUE_REQUIRED, 0) ; } @@ -100,6 +138,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int { $output->write('some message'); + if ($input->getOption('throw-unrecoverable')) { + throw new UnrecoverableMessageHandlingException('Unrecoverable exception message'); + } + + if ($input->getOption('throw-recoverable')) { + throw new RecoverableMessageHandlingException('Recoverable exception message'); + } + if ($input->getOption('throw')) { throw new \RuntimeException('exception message'); } From f755ca9c8d317f28bb6ca75337976c5fb6a9c745 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 10 Jul 2025 09:12:18 +0200 Subject: [PATCH 2/8] CS fixes --- Application.php | 36 ++++++------- CI/GithubActionReporter.php | 4 +- Color.php | 8 +-- Command/Command.php | 16 +++--- Command/CompleteCommand.php | 4 +- Command/DumpCompletionCommand.php | 4 +- Command/SignalableCommandInterface.php | 2 +- CommandLoader/ContainerCommandLoader.php | 2 +- CommandLoader/FactoryCommandLoader.php | 2 +- Completion/Suggestion.php | 2 +- Cursor.php | 14 ++--- DataCollector/CommandDataCollector.php | 6 +-- DependencyInjection/AddConsoleCommandPass.php | 8 +-- Descriptor/ApplicationDescription.php | 2 +- Descriptor/Descriptor.php | 2 +- Descriptor/MarkdownDescriptor.php | 4 +- Descriptor/ReStructuredTextDescriptor.php | 4 +- Descriptor/TextDescriptor.php | 20 +++---- Formatter/OutputFormatter.php | 2 +- Helper/DebugFormatterHelper.php | 16 +++--- Helper/DescriptorHelper.php | 2 +- Helper/FormatterHelper.php | 6 +-- Helper/Helper.php | 8 +-- Helper/HelperSet.php | 2 +- Helper/OutputWrapper.php | 6 +-- Helper/ProcessHelper.php | 6 +-- Helper/ProgressBar.php | 2 +- Helper/QuestionHelper.php | 2 +- Helper/SymfonyQuestionHelper.php | 12 ++--- Helper/Table.php | 32 ++++++------ Helper/TableCell.php | 2 +- Helper/TableCellStyle.php | 4 +- Input/ArgvInput.php | 20 +++---- Input/ArrayInput.php | 8 +-- Input/Input.php | 10 ++-- Input/InputArgument.php | 6 +-- Input/InputDefinition.php | 30 +++++------ Input/InputOption.php | 6 +-- Input/StringInput.php | 2 +- Logger/ConsoleLogger.php | 4 +- Messenger/RunCommandMessageHandler.php | 2 +- Output/AnsiColorMode.php | 6 +-- Output/ConsoleSectionOutput.php | 2 +- Output/TrimmedBufferOutput.php | 2 +- Question/ChoiceQuestion.php | 6 +-- Question/Question.php | 2 +- Style/SymfonyStyle.php | 16 +++--- Tester/Constraint/CommandIsSuccessful.php | 2 +- Tests/ApplicationTest.php | 8 +-- Tests/Command/CommandTest.php | 2 +- .../Command/SingleCommandApplicationTest.php | 2 +- .../Descriptor/AbstractDescriptorTestCase.php | 2 +- Tests/Helper/ProgressBarTest.php | 18 +++---- Tests/Helper/ProgressIndicatorTest.php | 2 +- Tests/Helper/TableTest.php | 52 +++++++++---------- Tests/Input/InputDefinitionTest.php | 4 +- .../RunCommandMessageHandlerTest.php | 2 +- Tests/Output/ConsoleSectionOutputTest.php | 6 +-- Tests/Question/ConfirmationQuestionTest.php | 2 +- 59 files changed, 233 insertions(+), 233 deletions(-) diff --git a/Application.php b/Application.php index b876bc971..c18d482b4 100644 --- a/Application.php +++ b/Application.php @@ -270,9 +270,9 @@ public function doRun(InputInterface $input, OutputInterface $output) $style = new SymfonyStyle($input, $output); $output->writeln(''); - $formattedBlock = (new FormatterHelper())->formatBlock(sprintf('Command "%s" is not defined.', $name), 'error', true); + $formattedBlock = (new FormatterHelper())->formatBlock(\sprintf('Command "%s" is not defined.', $name), 'error', true); $output->writeln($formattedBlock); - if (!$style->confirm(sprintf('Do you want to run "%s" instead? ', $alternative), false)) { + if (!$style->confirm(\sprintf('Do you want to run "%s" instead? ', $alternative), false)) { if (null !== $this->dispatcher) { $event = new ConsoleErrorEvent($input, $output, $e); $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); @@ -502,7 +502,7 @@ public function getLongVersion() { if ('UNKNOWN' !== $this->getName()) { if ('UNKNOWN' !== $this->getVersion()) { - return sprintf('%s %s', $this->getName(), $this->getVersion()); + return \sprintf('%s %s', $this->getName(), $this->getVersion()); } return $this->getName(); @@ -561,7 +561,7 @@ public function add(Command $command) } if (!$command->getName()) { - throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command))); + throw new LogicException(\sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command))); } $this->commands[$command->getName()] = $command; @@ -585,12 +585,12 @@ public function get(string $name) $this->init(); if (!$this->has($name)) { - throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); } // When the command has a different name than the one used at the command loader level if (!isset($this->commands[$name])) { - throw new CommandNotFoundException(sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); + throw new CommandNotFoundException(\sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); } $command = $this->commands[$name]; @@ -654,7 +654,7 @@ public function findNamespace(string $namespace): string $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces); if (empty($namespaces)) { - $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace); + $message = \sprintf('There are no commands defined in the "%s" namespace.', $namespace); if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { if (1 == \count($alternatives)) { @@ -671,7 +671,7 @@ public function findNamespace(string $namespace): string $exact = \in_array($namespace, $namespaces, true); if (\count($namespaces) > 1 && !$exact) { - throw new NamespaceNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces)); + throw new NamespaceNotFoundException(\sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces)); } return $exact ? $namespace : reset($namespaces); @@ -720,7 +720,7 @@ public function find(string $name) $this->findNamespace(substr($name, 0, $pos)); } - $message = sprintf('Command "%s" is not defined.', $name); + $message = \sprintf('Command "%s" is not defined.', $name); if ($alternatives = $this->findAlternatives($name, $allCommands)) { // remove hidden commands @@ -775,14 +775,14 @@ public function find(string $name) if (\count($commands) > 1) { $suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs)); - throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands)); + throw new CommandNotFoundException(\sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands)); } } $command = $this->get(reset($commands)); if ($command->isHidden()) { - throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); } return $command; @@ -857,7 +857,7 @@ public function renderThrowable(\Throwable $e, OutputInterface $output): void $this->doRenderThrowable($e, $output); if (null !== $this->runningCommand) { - $output->writeln(sprintf('%s', OutputFormatter::escape(sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); + $output->writeln(\sprintf('%s', OutputFormatter::escape(\sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); $output->writeln('', OutputInterface::VERBOSITY_QUIET); } } @@ -868,7 +868,7 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo $message = trim($e->getMessage()); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $class = get_debug_type($e); - $title = sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : ''); + $title = \sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : ''); $len = Helper::width($title); } else { $len = 0; @@ -892,14 +892,14 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo $messages = []; if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { - $messages[] = sprintf('%s', OutputFormatter::escape(sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); + $messages[] = \sprintf('%s', OutputFormatter::escape(\sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); } - $messages[] = $emptyLine = sprintf('%s', str_repeat(' ', $len)); + $messages[] = $emptyLine = \sprintf('%s', str_repeat(' ', $len)); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { - $messages[] = sprintf('%s%s', $title, str_repeat(' ', max(0, $len - Helper::width($title)))); + $messages[] = \sprintf('%s%s', $title, str_repeat(' ', max(0, $len - Helper::width($title)))); } foreach ($lines as $line) { - $messages[] = sprintf(' %s %s', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1])); + $messages[] = \sprintf(' %s %s', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1])); } $messages[] = $emptyLine; $messages[] = ''; @@ -926,7 +926,7 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo $file = $trace[$i]['file'] ?? 'n/a'; $line = $trace[$i]['line'] ?? 'n/a'; - $output->writeln(sprintf(' %s%s at %s:%s', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); + $output->writeln(\sprintf(' %s%s at %s:%s', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); } $output->writeln('', OutputInterface::VERBOSITY_QUIET); diff --git a/CI/GithubActionReporter.php b/CI/GithubActionReporter.php index 2cae6fd8b..28112c2a2 100644 --- a/CI/GithubActionReporter.php +++ b/CI/GithubActionReporter.php @@ -89,11 +89,11 @@ private function log(string $type, string $message, ?string $file = null, ?int $ if (!$file) { // No file provided, output the message solely: - $this->output->writeln(sprintf('::%s::%s', $type, $message)); + $this->output->writeln(\sprintf('::%s::%s', $type, $message)); return; } - $this->output->writeln(sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message)); + $this->output->writeln(\sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message)); } } diff --git a/Color.php b/Color.php index 60ed046a6..b1914c19a 100644 --- a/Color.php +++ b/Color.php @@ -60,7 +60,7 @@ public function __construct(string $foreground = '', string $background = '', ar foreach ($options as $option) { if (!isset(self::AVAILABLE_OPTIONS[$option])) { - throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS)))); + throw new InvalidArgumentException(\sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS)))); } $this->options[$option] = self::AVAILABLE_OPTIONS[$option]; @@ -88,7 +88,7 @@ public function set(): string return ''; } - return sprintf("\033[%sm", implode(';', $setCodes)); + return \sprintf("\033[%sm", implode(';', $setCodes)); } public function unset(): string @@ -107,7 +107,7 @@ public function unset(): string return ''; } - return sprintf("\033[%sm", implode(';', $unsetCodes)); + return \sprintf("\033[%sm", implode(';', $unsetCodes)); } private function parseColor(string $color, bool $background = false): string @@ -128,6 +128,6 @@ private function parseColor(string $color, bool $background = false): string return ($background ? '10' : '9').self::BRIGHT_COLORS[$color]; } - throw new InvalidArgumentException(sprintf('Invalid "%s" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS))))); + throw new InvalidArgumentException(\sprintf('Invalid "%s" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS))))); } } diff --git a/Command/Command.php b/Command/Command.php index 9f9cb2f53..3ede6ca6b 100644 --- a/Command/Command.php +++ b/Command/Command.php @@ -326,7 +326,7 @@ public function run(InputInterface $input, OutputInterface $output): int $statusCode = $this->execute($input, $output); if (!\is_int($statusCode)) { - throw new \TypeError(sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode))); + throw new \TypeError(\sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode))); } } @@ -446,7 +446,7 @@ public function getDefinition(): InputDefinition */ public function getNativeDefinition(): InputDefinition { - return $this->definition ?? throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class)); + return $this->definition ?? throw new LogicException(\sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class)); } /** @@ -464,7 +464,7 @@ public function addArgument(string $name, ?int $mode = null, string $description { $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : []; if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { - throw new \TypeError(sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); + throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); } $this->definition->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)); $this->fullDefinition?->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)); @@ -488,7 +488,7 @@ public function addOption(string $name, string|array|null $shortcut = null, ?int { $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : []; if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { - throw new \TypeError(sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); + throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); } $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)); $this->fullDefinition?->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)); @@ -662,7 +662,7 @@ public function getSynopsis(bool $short = false): string $key = $short ? 'short' : 'long'; if (!isset($this->synopsis[$key])) { - $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); + $this->synopsis[$key] = trim(\sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); } return $this->synopsis[$key]; @@ -676,7 +676,7 @@ public function getSynopsis(bool $short = false): string public function addUsage(string $usage): static { if (!str_starts_with($usage, $this->name)) { - $usage = sprintf('%s %s', $this->name, $usage); + $usage = \sprintf('%s %s', $this->name, $usage); } $this->usages[] = $usage; @@ -703,7 +703,7 @@ public function getUsages(): array public function getHelper(string $name): mixed { if (null === $this->helperSet) { - throw new LogicException(sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name)); + throw new LogicException(\sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name)); } return $this->helperSet->get($name); @@ -719,7 +719,7 @@ public function getHelper(string $name): mixed private function validateName(string $name): void { if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) { - throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name)); + throw new InvalidArgumentException(\sprintf('Command name "%s" is invalid.', $name)); } } } diff --git a/Command/CompleteCommand.php b/Command/CompleteCommand.php index 23be5577b..33f7f93c8 100644 --- a/Command/CompleteCommand.php +++ b/Command/CompleteCommand.php @@ -85,7 +85,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int // "symfony" must be kept for compat with the shell scripts generated by Symfony Console 5.4 - 6.1 $version = $input->getOption('symfony') ? '1' : $input->getOption('api-version'); if ($version && version_compare($version, self::COMPLETION_API_VERSION, '<')) { - $message = sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION); + $message = \sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION); $this->log($message); $output->writeln($message.' Install the Symfony completion script again by using the "completion" command.'); @@ -99,7 +99,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } if (!$completionOutput = $this->completionOutputs[$shell] ?? false) { - throw new \RuntimeException(sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs)))); + throw new \RuntimeException(\sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs)))); } $completionInput = $this->createCompletionInput($input); diff --git a/Command/DumpCompletionCommand.php b/Command/DumpCompletionCommand.php index 51b613a14..571425b88 100644 --- a/Command/DumpCompletionCommand.php +++ b/Command/DumpCompletionCommand.php @@ -108,9 +108,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output = $output->getErrorOutput(); } if ($shell) { - $output->writeln(sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, implode('", "', $supportedShells))); + $output->writeln(\sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, implode('", "', $supportedShells))); } else { - $output->writeln(sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); + $output->writeln(\sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); } return 2; diff --git a/Command/SignalableCommandInterface.php b/Command/SignalableCommandInterface.php index f8eb8e522..74d59b086 100644 --- a/Command/SignalableCommandInterface.php +++ b/Command/SignalableCommandInterface.php @@ -30,5 +30,5 @@ public function getSubscribedSignals(): array; * * @return int|false The exit code to return or false to continue the normal execution */ - public function handleSignal(int $signal, /* int|false $previousExitCode = 0 */); + public function handleSignal(int $signal/* , int|false $previousExitCode = 0 */); } diff --git a/CommandLoader/ContainerCommandLoader.php b/CommandLoader/ContainerCommandLoader.php index bfa0ac467..1638f2fd0 100644 --- a/CommandLoader/ContainerCommandLoader.php +++ b/CommandLoader/ContainerCommandLoader.php @@ -37,7 +37,7 @@ public function __construct(ContainerInterface $container, array $commandMap) public function get(string $name): Command { if (!$this->has($name)) { - throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } return $this->container->get($this->commandMap[$name]); diff --git a/CommandLoader/FactoryCommandLoader.php b/CommandLoader/FactoryCommandLoader.php index 9ced75aeb..ffe1b520c 100644 --- a/CommandLoader/FactoryCommandLoader.php +++ b/CommandLoader/FactoryCommandLoader.php @@ -39,7 +39,7 @@ public function has(string $name): bool public function get(string $name): Command { if (!isset($this->factories[$name])) { - throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } $factory = $this->factories[$name]; diff --git a/Completion/Suggestion.php b/Completion/Suggestion.php index 7392965a2..3251b079f 100644 --- a/Completion/Suggestion.php +++ b/Completion/Suggestion.php @@ -20,7 +20,7 @@ class Suggestion implements \Stringable { public function __construct( private readonly string $value, - private readonly string $description = '' + private readonly string $description = '', ) { } diff --git a/Cursor.php b/Cursor.php index 69fd3821c..45243c796 100644 --- a/Cursor.php +++ b/Cursor.php @@ -36,7 +36,7 @@ public function __construct(OutputInterface $output, $input = null) */ public function moveUp(int $lines = 1): static { - $this->output->write(sprintf("\x1b[%dA", $lines)); + $this->output->write(\sprintf("\x1b[%dA", $lines)); return $this; } @@ -46,7 +46,7 @@ public function moveUp(int $lines = 1): static */ public function moveDown(int $lines = 1): static { - $this->output->write(sprintf("\x1b[%dB", $lines)); + $this->output->write(\sprintf("\x1b[%dB", $lines)); return $this; } @@ -56,7 +56,7 @@ public function moveDown(int $lines = 1): static */ public function moveRight(int $columns = 1): static { - $this->output->write(sprintf("\x1b[%dC", $columns)); + $this->output->write(\sprintf("\x1b[%dC", $columns)); return $this; } @@ -66,7 +66,7 @@ public function moveRight(int $columns = 1): static */ public function moveLeft(int $columns = 1): static { - $this->output->write(sprintf("\x1b[%dD", $columns)); + $this->output->write(\sprintf("\x1b[%dD", $columns)); return $this; } @@ -76,7 +76,7 @@ public function moveLeft(int $columns = 1): static */ public function moveToColumn(int $column): static { - $this->output->write(sprintf("\x1b[%dG", $column)); + $this->output->write(\sprintf("\x1b[%dG", $column)); return $this; } @@ -86,7 +86,7 @@ public function moveToColumn(int $column): static */ public function moveToPosition(int $column, int $row): static { - $this->output->write(sprintf("\x1b[%d;%dH", $row + 1, $column)); + $this->output->write(\sprintf("\x1b[%d;%dH", $row + 1, $column)); return $this; } @@ -195,7 +195,7 @@ public function getCurrentPosition(): array $code = trim(fread($this->input, 1024)); - shell_exec(sprintf('stty %s', $sttyMode)); + shell_exec(\sprintf('stty %s', $sttyMode)); sscanf($code, "\033[%d;%dR", $row, $col); diff --git a/DataCollector/CommandDataCollector.php b/DataCollector/CommandDataCollector.php index 45138c7dc..3cbe72b59 100644 --- a/DataCollector/CommandDataCollector.php +++ b/DataCollector/CommandDataCollector.php @@ -118,7 +118,7 @@ public function getCommand(): array public function getInterruptedBySignal(): ?string { if (isset($this->data['interrupted_by_signal'])) { - return sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']); + return \sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']); } return null; @@ -204,7 +204,7 @@ public function getInteractiveInputs(): array public function getSignalable(): array { return array_map( - static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + static fn (int $signal): string => \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), $this->data['signalable'] ); } @@ -212,7 +212,7 @@ public function getSignalable(): array public function getHandledSignals(): array { $keys = array_map( - static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + static fn (int $signal): string => \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), array_keys($this->data['handled_signals']) ); diff --git a/DependencyInjection/AddConsoleCommandPass.php b/DependencyInjection/AddConsoleCommandPass.php index 27705ddb6..3cf05734b 100644 --- a/DependencyInjection/AddConsoleCommandPass.php +++ b/DependencyInjection/AddConsoleCommandPass.php @@ -48,10 +48,10 @@ public function process(ContainerBuilder $container) $aliases = $tags[0]['command']; } else { if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(Command::class)) { - throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); + throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); } $aliases = str_replace('%', '%%', $class::getDefaultName() ?? ''); } @@ -105,10 +105,10 @@ public function process(ContainerBuilder $container) if (!$description) { if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(Command::class)) { - throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); + throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); } $description = str_replace('%', '%%', $class::getDefaultDescription() ?? ''); } diff --git a/Descriptor/ApplicationDescription.php b/Descriptor/ApplicationDescription.php index ef9e8a63b..3f38379c9 100644 --- a/Descriptor/ApplicationDescription.php +++ b/Descriptor/ApplicationDescription.php @@ -73,7 +73,7 @@ public function getCommands(): array public function getCommand(string $name): Command { if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) { - throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } return $this->commands[$name] ?? $this->aliases[$name]; diff --git a/Descriptor/Descriptor.php b/Descriptor/Descriptor.php index 7b2509c60..2143a17c3 100644 --- a/Descriptor/Descriptor.php +++ b/Descriptor/Descriptor.php @@ -38,7 +38,7 @@ public function describe(OutputInterface $output, object $object, array $options $object instanceof InputDefinition => $this->describeInputDefinition($object, $options), $object instanceof Command => $this->describeCommand($object, $options), $object instanceof Application => $this->describeApplication($object, $options), - default => throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_debug_type($object))), + default => throw new InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', get_debug_type($object))), }; } diff --git a/Descriptor/MarkdownDescriptor.php b/Descriptor/MarkdownDescriptor.php index b3f16ee90..8b7075943 100644 --- a/Descriptor/MarkdownDescriptor.php +++ b/Descriptor/MarkdownDescriptor.php @@ -149,7 +149,7 @@ protected function describeApplication(Application $application, array $options } $this->write("\n\n"); - $this->write(implode("\n", array_map(fn ($commandName) => sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())), $namespace['commands']))); + $this->write(implode("\n", array_map(fn ($commandName) => \sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())), $namespace['commands']))); } foreach ($description->getCommands() as $command) { @@ -162,7 +162,7 @@ private function getApplicationTitle(Application $application): string { if ('UNKNOWN' !== $application->getName()) { if ('UNKNOWN' !== $application->getVersion()) { - return sprintf('%s %s', $application->getName(), $application->getVersion()); + return \sprintf('%s %s', $application->getName(), $application->getVersion()); } return $application->getName(); diff --git a/Descriptor/ReStructuredTextDescriptor.php b/Descriptor/ReStructuredTextDescriptor.php index d4423fd34..a2b754276 100644 --- a/Descriptor/ReStructuredTextDescriptor.php +++ b/Descriptor/ReStructuredTextDescriptor.php @@ -167,7 +167,7 @@ private function getApplicationTitle(Application $application): string return 'Console Tool'; } if ('UNKNOWN' !== $application->getVersion()) { - return sprintf('%s %s', $application->getName(), $application->getVersion()); + return \sprintf('%s %s', $application->getName(), $application->getVersion()); } return $application->getName(); @@ -209,7 +209,7 @@ private function createTableOfContents(ApplicationDescription $description, Appl $commands = $this->removeAliasesAndHiddenCommands($commands); $this->write("\n\n"); - $this->write(implode("\n", array_map(static fn ($commandName) => sprintf('- `%s`_', $commandName), array_keys($commands)))); + $this->write(implode("\n", array_map(static fn ($commandName) => \sprintf('- `%s`_', $commandName), array_keys($commands)))); } } diff --git a/Descriptor/TextDescriptor.php b/Descriptor/TextDescriptor.php index d04d10238..51c411f46 100644 --- a/Descriptor/TextDescriptor.php +++ b/Descriptor/TextDescriptor.php @@ -31,7 +31,7 @@ class TextDescriptor extends Descriptor protected function describeInputArgument(InputArgument $argument, array $options = []): void { if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) { - $default = sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); } else { $default = ''; } @@ -39,7 +39,7 @@ protected function describeInputArgument(InputArgument $argument, array $options $totalWidth = $options['total_width'] ?? Helper::width($argument->getName()); $spacingWidth = $totalWidth - \strlen($argument->getName()); - $this->writeText(sprintf(' %s %s%s%s', + $this->writeText(\sprintf(' %s %s%s%s', $argument->getName(), str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after @@ -51,7 +51,7 @@ protected function describeInputArgument(InputArgument $argument, array $options protected function describeInputOption(InputOption $option, array $options = []): void { if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) { - $default = sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); } else { $default = ''; } @@ -66,14 +66,14 @@ protected function describeInputOption(InputOption $option, array $options = []) } $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]); - $synopsis = sprintf('%s%s', - $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ', - sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value) + $synopsis = \sprintf('%s%s', + $option->getShortcut() ? \sprintf('-%s, ', $option->getShortcut()) : ' ', + \sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value) ); $spacingWidth = $totalWidth - Helper::width($synopsis); - $this->writeText(sprintf(' %s %s%s%s%s', + $this->writeText(\sprintf(' %s %s%s%s%s', $synopsis, str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after @@ -166,7 +166,7 @@ protected function describeApplication(Application $application, array $options $width = $this->getColumnWidth($description->getCommands()); foreach ($description->getCommands() as $command) { - $this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); + $this->writeText(\sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); $this->writeText("\n"); } } else { @@ -196,7 +196,7 @@ protected function describeApplication(Application $application, array $options $width = $this->getColumnWidth(array_merge(...array_values(array_map(fn ($namespace) => array_intersect($namespace['commands'], array_keys($commands)), array_values($namespaces))))); if ($describedNamespace) { - $this->writeText(sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); + $this->writeText(\sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); } else { $this->writeText('Available commands:', $options); } @@ -218,7 +218,7 @@ protected function describeApplication(Application $application, array $options $spacingWidth = $width - Helper::width($name); $command = $commands[$name]; $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : ''; - $this->writeText(sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options); + $this->writeText(\sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options); } } diff --git a/Formatter/OutputFormatter.php b/Formatter/OutputFormatter.php index 3e4897c33..52d831620 100644 --- a/Formatter/OutputFormatter.php +++ b/Formatter/OutputFormatter.php @@ -112,7 +112,7 @@ public function hasStyle(string $name): bool public function getStyle(string $name): OutputFormatterStyleInterface { if (!$this->hasStyle($name)) { - throw new InvalidArgumentException(sprintf('Undefined style: "%s".', $name)); + throw new InvalidArgumentException(\sprintf('Undefined style: "%s".', $name)); } return $this->styles[strtolower($name)]; diff --git a/Helper/DebugFormatterHelper.php b/Helper/DebugFormatterHelper.php index 9ea7fb914..dfdb8a82c 100644 --- a/Helper/DebugFormatterHelper.php +++ b/Helper/DebugFormatterHelper.php @@ -31,7 +31,7 @@ public function start(string $id, string $message, string $prefix = 'RUN'): stri { $this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)]; - return sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); + return \sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); } /** @@ -47,22 +47,22 @@ public function progress(string $id, string $buffer, bool $error = false, string unset($this->started[$id]['out']); } if (!isset($this->started[$id]['err'])) { - $message .= sprintf('%s %s ', $this->getBorder($id), $errorPrefix); + $message .= \sprintf('%s %s ', $this->getBorder($id), $errorPrefix); $this->started[$id]['err'] = true; } - $message .= str_replace("\n", sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); + $message .= str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); } else { if (isset($this->started[$id]['err'])) { $message .= "\n"; unset($this->started[$id]['err']); } if (!isset($this->started[$id]['out'])) { - $message .= sprintf('%s %s ', $this->getBorder($id), $prefix); + $message .= \sprintf('%s %s ', $this->getBorder($id), $prefix); $this->started[$id]['out'] = true; } - $message .= str_replace("\n", sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); + $message .= str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); } return $message; @@ -76,10 +76,10 @@ public function stop(string $id, string $message, bool $successful, string $pref $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : ''; if ($successful) { - return sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + return \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); } - $message = sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + $message = \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); unset($this->started[$id]['out'], $this->started[$id]['err']); @@ -88,7 +88,7 @@ public function stop(string $id, string $message, bool $successful, string $pref private function getBorder(string $id): string { - return sprintf(' ', self::COLORS[$this->started[$id]['border']]); + return \sprintf(' ', self::COLORS[$this->started[$id]['border']]); } public function getName(): string diff --git a/Helper/DescriptorHelper.php b/Helper/DescriptorHelper.php index eb32bce8f..fda6779b9 100644 --- a/Helper/DescriptorHelper.php +++ b/Helper/DescriptorHelper.php @@ -62,7 +62,7 @@ public function describe(OutputInterface $output, ?object $object, array $option ], $options); if (!isset($this->descriptors[$options['format']])) { - throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format'])); + throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $options['format'])); } $descriptor = $this->descriptors[$options['format']]; diff --git a/Helper/FormatterHelper.php b/Helper/FormatterHelper.php index 279e4c799..3646b3d6f 100644 --- a/Helper/FormatterHelper.php +++ b/Helper/FormatterHelper.php @@ -25,7 +25,7 @@ class FormatterHelper extends Helper */ public function formatSection(string $section, string $message, string $style = 'info'): string { - return sprintf('<%s>[%s] %s', $style, $section, $style, $message); + return \sprintf('<%s>[%s] %s', $style, $section, $style, $message); } /** @@ -41,7 +41,7 @@ public function formatBlock(string|array $messages, string $style, bool $large = $lines = []; foreach ($messages as $message) { $message = OutputFormatter::escape($message); - $lines[] = sprintf($large ? ' %s ' : ' %s ', $message); + $lines[] = \sprintf($large ? ' %s ' : ' %s ', $message); $len = max(self::width($message) + ($large ? 4 : 2), $len); } @@ -54,7 +54,7 @@ public function formatBlock(string|array $messages, string $style, bool $large = } for ($i = 0; isset($messages[$i]); ++$i) { - $messages[$i] = sprintf('<%s>%s', $style, $messages[$i], $style); + $messages[$i] = \sprintf('<%s>%s', $style, $messages[$i], $style); } return implode("\n", $messages); diff --git a/Helper/Helper.php b/Helper/Helper.php index 5999537d7..eec328498 100644 --- a/Helper/Helper.php +++ b/Helper/Helper.php @@ -142,18 +142,18 @@ public static function formatTime(int|float $secs, int $precision = 1) public static function formatMemory(int $memory) { if ($memory >= 1024 * 1024 * 1024) { - return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); + return \sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); } if ($memory >= 1024 * 1024) { - return sprintf('%.1f MiB', $memory / 1024 / 1024); + return \sprintf('%.1f MiB', $memory / 1024 / 1024); } if ($memory >= 1024) { - return sprintf('%d KiB', $memory / 1024); + return \sprintf('%d KiB', $memory / 1024); } - return sprintf('%d B', $memory); + return \sprintf('%d B', $memory); } /** diff --git a/Helper/HelperSet.php b/Helper/HelperSet.php index f8c74ca2c..8deb22ee7 100644 --- a/Helper/HelperSet.php +++ b/Helper/HelperSet.php @@ -64,7 +64,7 @@ public function has(string $name): bool public function get(string $name): HelperInterface { if (!$this->has($name)) { - throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name)); + throw new InvalidArgumentException(\sprintf('The helper "%s" is not defined.', $name)); } return $this->helpers[$name]; diff --git a/Helper/OutputWrapper.php b/Helper/OutputWrapper.php index 2ec819c74..a615ed2f9 100644 --- a/Helper/OutputWrapper.php +++ b/Helper/OutputWrapper.php @@ -49,7 +49,7 @@ final class OutputWrapper private const URL_PATTERN = 'https?://\S+'; public function __construct( - private bool $allowCutUrls = false + private bool $allowCutUrls = false, ) { } @@ -59,7 +59,7 @@ public function wrap(string $text, int $width, string $break = "\n"): string return $text; } - $tagPattern = sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT); + $tagPattern = \sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT); $limitPattern = "{1,$width}"; $patternBlocks = [$tagPattern]; if (!$this->allowCutUrls) { @@ -68,7 +68,7 @@ public function wrap(string $text, int $width, string $break = "\n"): string $patternBlocks[] = '.'; $blocks = implode('|', $patternBlocks); $rowPattern = "(?:$blocks)$limitPattern"; - $pattern = sprintf('#(?:((?>(%1$s)((?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|(%1$s))(?:\r?\n)?|(?:\r?\n|$))#imux', $rowPattern); + $pattern = \sprintf('#(?:((?>(%1$s)((?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|(%1$s))(?:\r?\n)?|(?:\r?\n|$))#imux', $rowPattern); $output = rtrim(preg_replace($pattern, '\\1'.$break, $text), $break); return str_replace(' '.$break, $break, $output); diff --git a/Helper/ProcessHelper.php b/Helper/ProcessHelper.php index 3ef6f71f7..ae55a83c2 100644 --- a/Helper/ProcessHelper.php +++ b/Helper/ProcessHelper.php @@ -55,7 +55,7 @@ public function run(OutputInterface $output, array|Process $cmd, ?string $error $process = $cmd[0]; unset($cmd[0]); } else { - throw new \InvalidArgumentException(sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); + throw new \InvalidArgumentException(\sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); } if ($verbosity <= $output->getVerbosity()) { @@ -69,12 +69,12 @@ public function run(OutputInterface $output, array|Process $cmd, ?string $error $process->run($callback, $cmd); if ($verbosity <= $output->getVerbosity()) { - $message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode()); + $message = $process->isSuccessful() ? 'Command ran successfully' : \sprintf('%s Command did not run successfully', $process->getExitCode()); $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful())); } if (!$process->isSuccessful() && null !== $error) { - $output->writeln(sprintf('%s', $this->escapeString($error))); + $output->writeln(\sprintf('%s', $this->escapeString($error))); } return $process; diff --git a/Helper/ProgressBar.php b/Helper/ProgressBar.php index 3dc06d7b4..8143acaff 100644 --- a/Helper/ProgressBar.php +++ b/Helper/ProgressBar.php @@ -603,7 +603,7 @@ private function buildLine(): string } if (isset($matches[2])) { - $text = sprintf('%'.$matches[2], $text); + $text = \sprintf('%'.$matches[2], $text); } return $text; diff --git a/Helper/QuestionHelper.php b/Helper/QuestionHelper.php index b40b13191..3d9091d2b 100644 --- a/Helper/QuestionHelper.php +++ b/Helper/QuestionHelper.php @@ -220,7 +220,7 @@ protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string foreach ($choices as $key => $value) { $padding = str_repeat(' ', $maxWidth - self::width($key)); - $messages[] = sprintf(" [<$tag>%s$padding] %s", $key, $value); + $messages[] = \sprintf(" [<$tag>%s$padding] %s", $key, $value); } return $messages; diff --git a/Helper/SymfonyQuestionHelper.php b/Helper/SymfonyQuestionHelper.php index 8ebc84376..11b4e4238 100644 --- a/Helper/SymfonyQuestionHelper.php +++ b/Helper/SymfonyQuestionHelper.php @@ -34,17 +34,17 @@ protected function writePrompt(OutputInterface $output, Question $question) $default = $question->getDefault(); if ($question->isMultiline()) { - $text .= sprintf(' (press %s to continue)', $this->getEofShortcut()); + $text .= \sprintf(' (press %s to continue)', $this->getEofShortcut()); } switch (true) { case null === $default: - $text = sprintf(' %s:', $text); + $text = \sprintf(' %s:', $text); break; case $question instanceof ConfirmationQuestion: - $text = sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); + $text = \sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); break; @@ -56,18 +56,18 @@ protected function writePrompt(OutputInterface $output, Question $question) $default[$key] = $choices[trim($value)]; } - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); break; case $question instanceof ChoiceQuestion: $choices = $question->getChoices(); - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); break; default: - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); } $output->writeln($text); diff --git a/Helper/Table.php b/Helper/Table.php index 0ef771dd4..469d228d6 100644 --- a/Helper/Table.php +++ b/Helper/Table.php @@ -83,7 +83,7 @@ public static function getStyleDefinition(string $name): TableStyle { self::$styles ??= self::initStyles(); - return self::$styles[$name] ?? throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + return self::$styles[$name] ?? throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); } /** @@ -168,7 +168,7 @@ public function setColumnWidths(array $widths): static public function setColumnMaxWidth(int $columnIndex, int $width): static { if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) { - throw new \LogicException(sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter()))); + throw new \LogicException(\sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter()))); } $this->columnMaxWidths[$columnIndex] = $width; @@ -237,7 +237,7 @@ public function addRow(TableSeparator|array $row): static public function appendRow(TableSeparator|array $row): static { if (!$this->output instanceof ConsoleSectionOutput) { - throw new RuntimeException(sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); + throw new RuntimeException(\sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); } if ($this->rendered) { @@ -370,14 +370,14 @@ public function render() foreach ($parts as $idx => $part) { if ($headers && !$containsColspan) { if (0 === $idx) { - $rows[] = [sprintf( + $rows[] = [\sprintf( '%s%s: %s', str_repeat(' ', $maxHeaderLength - Helper::width(Helper::removeDecoration($formatter, $headers[$i] ?? ''))), $headers[$i] ?? '', $part )]; } else { - $rows[] = [sprintf( + $rows[] = [\sprintf( '%s %s', str_pad('', $maxHeaderLength, ' ', \STR_PAD_LEFT), $part @@ -497,12 +497,12 @@ private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $ti } if (null !== $title) { - $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title))); + $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = \sprintf($titleFormat, $title))); $markupLength = Helper::width($markup); if ($titleLength > $limit = $markupLength - 4) { $titleLength = $limit; - $formatLength = Helper::width(Helper::removeDecoration($formatter, sprintf($titleFormat, ''))); - $formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...'); + $formatLength = Helper::width(Helper::removeDecoration($formatter, \sprintf($titleFormat, ''))); + $formattedTitle = \sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...'); } $titleStart = intdiv($markupLength - $titleLength, 2); @@ -513,7 +513,7 @@ private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $ti } } - $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup)); + $this->output->writeln(\sprintf($this->style->getBorderFormat(), $markup)); } /** @@ -523,7 +523,7 @@ private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string { $borders = $this->style->getBorderChars(); - return sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); + return \sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); } /** @@ -568,11 +568,11 @@ private function renderCell(array $row, int $column, string $cellFormat): string $style = $this->getColumnStyle($column); if ($cell instanceof TableSeparator) { - return sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width)); + return \sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width)); } $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell)); - $content = sprintf($style->getCellRowContentFormat(), $cell); + $content = \sprintf($style->getCellRowContentFormat(), $cell); $padType = $style->getPadType(); if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) { @@ -597,7 +597,7 @@ private function renderCell(array $row, int $column, string $cellFormat): string $padType = $cell->getStyle()->getPadByAlign(); } - return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType)); + return \sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType)); } /** @@ -734,7 +734,7 @@ private function fillNextRows(array $rows, int $line): array $unmergedRows = []; foreach ($rows[$line] as $column => $cell) { if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !$cell instanceof \Stringable) { - throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell))); + throw new InvalidArgumentException(\sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell))); } if ($cell instanceof TableCell && $cell->getRowspan() > 1) { $nbLines = $cell->getRowspan() - 1; @@ -879,7 +879,7 @@ private function calculateColumnsWidth(iterable $groups): void private function getColumnSeparatorWidth(): int { - return Helper::width(sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); + return Helper::width(\sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); } private function getCellWidth(array $row, int $column): int @@ -962,6 +962,6 @@ private function resolveStyle(TableStyle|string $name): TableStyle return $name; } - return self::$styles[$name] ?? throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + return self::$styles[$name] ?? throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); } } diff --git a/Helper/TableCell.php b/Helper/TableCell.php index 394b2bc95..ead32f283 100644 --- a/Helper/TableCell.php +++ b/Helper/TableCell.php @@ -31,7 +31,7 @@ public function __construct(string $value = '', array $options = []) // check option names if ($diff = array_diff(array_keys($options), array_keys($this->options))) { - throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff))); + throw new InvalidArgumentException(\sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff))); } if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) { diff --git a/Helper/TableCellStyle.php b/Helper/TableCellStyle.php index 9419dcb40..1b1ef276e 100644 --- a/Helper/TableCellStyle.php +++ b/Helper/TableCellStyle.php @@ -43,11 +43,11 @@ class TableCellStyle public function __construct(array $options = []) { if ($diff = array_diff(array_keys($options), array_keys($this->options))) { - throw new InvalidArgumentException(sprintf('The TableCellStyle does not support the following options: \'%s\'.', implode('\', \'', $diff))); + throw new InvalidArgumentException(\sprintf('The TableCellStyle does not support the following options: \'%s\'.', implode('\', \'', $diff))); } if (isset($options['align']) && !\array_key_exists($options['align'], self::ALIGN_MAP)) { - throw new InvalidArgumentException(sprintf('Wrong align value. Value must be following: \'%s\'.', implode('\', \'', array_keys(self::ALIGN_MAP)))); + throw new InvalidArgumentException(\sprintf('Wrong align value. Value must be following: \'%s\'.', implode('\', \'', array_keys(self::ALIGN_MAP)))); } $this->options = array_merge($this->options, $options); diff --git a/Input/ArgvInput.php b/Input/ArgvInput.php index ab9f28c54..a33092aee 100644 --- a/Input/ArgvInput.php +++ b/Input/ArgvInput.php @@ -122,7 +122,7 @@ private function parseShortOptionSet(string $name): void for ($i = 0; $i < $len; ++$i) { if (!$this->definition->hasShortcut($name[$i])) { $encoding = mb_detect_encoding($name, null, true); - throw new RuntimeException(sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding))); + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding))); } $option = $this->definition->getOptionForShortcut($name[$i]); @@ -183,14 +183,14 @@ private function parseArgument(string $token): void if (\count($all)) { if ($symfonyCommandName) { - $message = sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all))); + $message = \sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all))); } else { - $message = sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))); + $message = \sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))); } } elseif ($symfonyCommandName) { - $message = sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); + $message = \sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); } else { - $message = sprintf('No arguments expected, got "%s".', $token); + $message = \sprintf('No arguments expected, got "%s".', $token); } throw new RuntimeException($message); @@ -205,7 +205,7 @@ private function parseArgument(string $token): void private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { - throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut)); + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', $shortcut)); } $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); @@ -220,12 +220,12 @@ private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { - throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option does not exist.', $name)); } $optionName = $this->definition->negationToName($name); if (null !== $value) { - throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); } $this->options[$optionName] = false; @@ -235,7 +235,7 @@ private function addLongOption(string $name, mixed $value): void $option = $this->definition->getOption($name); if (null !== $value && !$option->acceptValue()) { - throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); } if (\in_array($value, ['', null], true) && $option->acceptValue() && \count($this->parsed)) { @@ -251,7 +251,7 @@ private function addLongOption(string $name, mixed $value): void if (null === $value) { if ($option->isValueRequired()) { - throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option requires a value.', $name)); } if (!$option->isArray() && !$option->isValueOptional()) { diff --git a/Input/ArrayInput.php b/Input/ArrayInput.php index c1bc914ca..b9f753394 100644 --- a/Input/ArrayInput.php +++ b/Input/ArrayInput.php @@ -140,7 +140,7 @@ protected function parse() private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { - throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut)); + throw new InvalidOptionException(\sprintf('The "-%s" option does not exist.', $shortcut)); } $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); @@ -156,7 +156,7 @@ private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { - throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name)); + throw new InvalidOptionException(\sprintf('The "--%s" option does not exist.', $name)); } $optionName = $this->definition->negationToName($name); @@ -169,7 +169,7 @@ private function addLongOption(string $name, mixed $value): void if (null === $value) { if ($option->isValueRequired()) { - throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name)); + throw new InvalidOptionException(\sprintf('The "--%s" option requires a value.', $name)); } if (!$option->isValueOptional()) { @@ -188,7 +188,7 @@ private function addLongOption(string $name, mixed $value): void private function addArgument(string|int $name, mixed $value): void { if (!$this->definition->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $this->arguments[$name] = $value; diff --git a/Input/Input.php b/Input/Input.php index 1c21573bc..d3a3c7fd2 100644 --- a/Input/Input.php +++ b/Input/Input.php @@ -74,7 +74,7 @@ public function validate() $missingArguments = array_filter(array_keys($definition->getArguments()), fn ($argument) => !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired()); if (\count($missingArguments) > 0) { - throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); + throw new RuntimeException(\sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); } } @@ -99,7 +99,7 @@ public function getArguments(): array public function getArgument(string $name): mixed { if (!$this->definition->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault(); @@ -111,7 +111,7 @@ public function getArgument(string $name): mixed public function setArgument(string $name, mixed $value) { if (!$this->definition->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $this->arguments[$name] = $value; @@ -138,7 +138,7 @@ public function getOption(string $name): mixed } if (!$this->definition->hasOption($name)) { - throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); } return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); @@ -154,7 +154,7 @@ public function setOption(string $name, mixed $value) return; } elseif (!$this->definition->hasOption($name)) { - throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); } $this->options[$name] = $value; diff --git a/Input/InputArgument.php b/Input/InputArgument.php index 4ef79feb7..fd203919f 100644 --- a/Input/InputArgument.php +++ b/Input/InputArgument.php @@ -31,7 +31,7 @@ class InputArgument private string $name; private int $mode; - private string|int|bool|array|null|float $default; + private string|int|bool|array|float|null $default; private array|\Closure $suggestedValues; private string $description; @@ -49,7 +49,7 @@ public function __construct(string $name, ?int $mode = null, string $description if (null === $mode) { $mode = self::OPTIONAL; } elseif ($mode > 7 || $mode < 1) { - throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode)); + throw new InvalidArgumentException(\sprintf('Argument mode "%s" is not valid.', $mode)); } $this->name = $name; @@ -137,7 +137,7 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti { $values = $this->suggestedValues; if ($values instanceof \Closure && !\is_array($values = $values($input))) { - throw new LogicException(sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); + throw new LogicException(\sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); } if ($values) { $suggestions->suggestValues($values); diff --git a/Input/InputDefinition.php b/Input/InputDefinition.php index b7162d770..b5c202838 100644 --- a/Input/InputDefinition.php +++ b/Input/InputDefinition.php @@ -105,15 +105,15 @@ public function addArguments(?array $arguments = []) public function addArgument(InputArgument $argument) { if (isset($this->arguments[$argument->getName()])) { - throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName())); + throw new LogicException(\sprintf('An argument with name "%s" already exists.', $argument->getName())); } if (null !== $this->lastArrayArgument) { - throw new LogicException(sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); } if ($argument->isRequired() && null !== $this->lastOptionalArgument) { - throw new LogicException(sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); } if ($argument->isArray()) { @@ -137,7 +137,7 @@ public function addArgument(InputArgument $argument) public function getArgument(string|int $name): InputArgument { if (!$this->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments; @@ -231,16 +231,16 @@ public function addOptions(array $options = []) public function addOption(InputOption $option) { if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { - throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName())); + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); } if (isset($this->negations[$option->getName()])) { - throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName())); + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); } if ($option->getShortcut()) { foreach (explode('|', $option->getShortcut()) as $shortcut) { if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) { - throw new LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut)); + throw new LogicException(\sprintf('An option with shortcut "%s" already exists.', $shortcut)); } } } @@ -255,7 +255,7 @@ public function addOption(InputOption $option) if ($option->isNegatable()) { $negatedName = 'no-'.$option->getName(); if (isset($this->options[$negatedName])) { - throw new LogicException(sprintf('An option named "%s" already exists.', $negatedName)); + throw new LogicException(\sprintf('An option named "%s" already exists.', $negatedName)); } $this->negations[$negatedName] = $option->getName(); } @@ -269,7 +269,7 @@ public function addOption(InputOption $option) public function getOption(string $name): InputOption { if (!$this->hasOption($name)) { - throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $name)); } return $this->options[$name]; @@ -343,7 +343,7 @@ public function getOptionDefaults(): array public function shortcutToName(string $shortcut): string { if (!isset($this->shortcuts[$shortcut])) { - throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); + throw new InvalidArgumentException(\sprintf('The "-%s" option does not exist.', $shortcut)); } return $this->shortcuts[$shortcut]; @@ -359,7 +359,7 @@ public function shortcutToName(string $shortcut): string public function negationToName(string $negation): string { if (!isset($this->negations[$negation])) { - throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $negation)); + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $negation)); } return $this->negations[$negation]; @@ -378,7 +378,7 @@ public function getSynopsis(bool $short = false): string foreach ($this->getOptions() as $option) { $value = ''; if ($option->acceptValue()) { - $value = sprintf( + $value = \sprintf( ' %s%s%s', $option->isValueOptional() ? '[' : '', strtoupper($option->getName()), @@ -386,9 +386,9 @@ public function getSynopsis(bool $short = false): string ); } - $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : ''; - $negation = $option->isNegatable() ? sprintf('|--no-%s', $option->getName()) : ''; - $elements[] = sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); + $shortcut = $option->getShortcut() ? \sprintf('-%s|', $option->getShortcut()) : ''; + $negation = $option->isNegatable() ? \sprintf('|--no-%s', $option->getName()) : ''; + $elements[] = \sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); } } diff --git a/Input/InputOption.php b/Input/InputOption.php index bb533801f..3adc8c424 100644 --- a/Input/InputOption.php +++ b/Input/InputOption.php @@ -53,7 +53,7 @@ class InputOption private string $name; private string|array|null $shortcut; private int $mode; - private string|int|bool|array|null|float $default; + private string|int|bool|array|float|null $default; private array|\Closure $suggestedValues; private string $description; @@ -95,7 +95,7 @@ public function __construct(string $name, string|array|null $shortcut = null, ?i if (null === $mode) { $mode = self::VALUE_NONE; } elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) { - throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode)); + throw new InvalidArgumentException(\sprintf('Option mode "%s" is not valid.', $mode)); } $this->name = $name; @@ -231,7 +231,7 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti { $values = $this->suggestedValues; if ($values instanceof \Closure && !\is_array($values = $values($input))) { - throw new LogicException(sprintf('Closure for option "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); + throw new LogicException(\sprintf('Closure for option "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); } if ($values) { $suggestions->suggestValues($values); diff --git a/Input/StringInput.php b/Input/StringInput.php index 82bd21440..9b94784af 100644 --- a/Input/StringInput.php +++ b/Input/StringInput.php @@ -72,7 +72,7 @@ private function tokenize(string $input): array $token .= $match[1]; } else { // should never happen - throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10))); + throw new InvalidArgumentException(\sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10))); } $cursor += \strlen($match[0]); diff --git a/Logger/ConsoleLogger.php b/Logger/ConsoleLogger.php index fddef50cd..70432b7de 100644 --- a/Logger/ConsoleLogger.php +++ b/Logger/ConsoleLogger.php @@ -62,7 +62,7 @@ public function __construct(OutputInterface $output, array $verbosityLevelMap = public function log($level, $message, array $context = []): void { if (!isset($this->verbosityLevelMap[$level])) { - throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level)); + throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $level)); } $output = $this->output; @@ -78,7 +78,7 @@ public function log($level, $message, array $context = []): void // the if condition check isn't necessary -- it's the same one that $output will do internally anyway. // We only do it for efficiency here as the message formatting is relatively expensive. if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { - $output->writeln(sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); + $output->writeln(\sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); } } diff --git a/Messenger/RunCommandMessageHandler.php b/Messenger/RunCommandMessageHandler.php index 2d698c734..3f4286542 100644 --- a/Messenger/RunCommandMessageHandler.php +++ b/Messenger/RunCommandMessageHandler.php @@ -44,7 +44,7 @@ public function __invoke(RunCommandMessage $message): RunCommandContext } if ($message->throwOnFailure && Command::SUCCESS !== $exitCode) { - throw new RunCommandFailedException(sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch())); + throw new RunCommandFailedException(\sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch())); } return new RunCommandContext($message, $exitCode, $output->fetch()); diff --git a/Output/AnsiColorMode.php b/Output/AnsiColorMode.php index 5f9f744fe..dcdd1d5c4 100644 --- a/Output/AnsiColorMode.php +++ b/Output/AnsiColorMode.php @@ -51,7 +51,7 @@ public function convertFromHexToAnsiColorCode(string $hexColor): string } if (6 !== \strlen($hexColor)) { - throw new InvalidArgumentException(sprintf('Invalid "#%s" color.', $hexColor)); + throw new InvalidArgumentException(\sprintf('Invalid "#%s" color.', $hexColor)); } $color = hexdec($hexColor); @@ -63,7 +63,7 @@ public function convertFromHexToAnsiColorCode(string $hexColor): string 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) + self::Ansi24 => \sprintf('8;2;%d;%d;%d', $r, $g, $b), }; } @@ -72,7 +72,7 @@ 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}.") + default => throw new InvalidArgumentException("RGB cannot be converted to {$this->name}."), }; } diff --git a/Output/ConsoleSectionOutput.php b/Output/ConsoleSectionOutput.php index f2d7933bb..04d587cf2 100644 --- a/Output/ConsoleSectionOutput.php +++ b/Output/ConsoleSectionOutput.php @@ -229,7 +229,7 @@ private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFr if ($numberOfLinesToClear > 0) { // move cursor up n lines - parent::doWrite(sprintf("\x1b[%dA", $numberOfLinesToClear), false); + parent::doWrite(\sprintf("\x1b[%dA", $numberOfLinesToClear), false); // erase to end of screen parent::doWrite("\x1b[0J", false); } diff --git a/Output/TrimmedBufferOutput.php b/Output/TrimmedBufferOutput.php index 23a2be8c3..90ee45aae 100644 --- a/Output/TrimmedBufferOutput.php +++ b/Output/TrimmedBufferOutput.php @@ -27,7 +27,7 @@ class TrimmedBufferOutput extends Output public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null) { if ($maxLength <= 0) { - throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); + throw new InvalidArgumentException(\sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); } parent::__construct($verbosity, $decorated, $formatter); diff --git a/Question/ChoiceQuestion.php b/Question/ChoiceQuestion.php index 465f3184f..9445ccc0c 100644 --- a/Question/ChoiceQuestion.php +++ b/Question/ChoiceQuestion.php @@ -120,7 +120,7 @@ private function getDefaultValidator(): callable if ($multiselect) { // Check for a separated comma values if (!preg_match('/^[^,]+(?:,[^,]+)*$/', (string) $selected, $matches)) { - throw new InvalidArgumentException(sprintf($errorMessage, $selected)); + throw new InvalidArgumentException(\sprintf($errorMessage, $selected)); } $selectedChoices = explode(',', (string) $selected); @@ -144,7 +144,7 @@ private function getDefaultValidator(): callable } if (\count($results) > 1) { - throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results))); + throw new InvalidArgumentException(\sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results))); } $result = array_search($value, $choices); @@ -160,7 +160,7 @@ private function getDefaultValidator(): callable } if (false === $result) { - throw new InvalidArgumentException(sprintf($errorMessage, $value)); + throw new InvalidArgumentException(\sprintf($errorMessage, $value)); } // For associative choices, consistently return the key as string: diff --git a/Question/Question.php b/Question/Question.php index 94c688fa8..ecbde56d5 100644 --- a/Question/Question.php +++ b/Question/Question.php @@ -27,7 +27,7 @@ class Question private bool $hiddenFallback = true; private ?\Closure $autocompleterCallback = null; private ?\Closure $validator = null; - private string|int|bool|null|float $default; + private string|int|bool|float|null $default; private ?\Closure $normalizer = null; private bool $trimmable = true; private bool $multiline = false; diff --git a/Style/SymfonyStyle.php b/Style/SymfonyStyle.php index 03bda8784..135f4fd0e 100644 --- a/Style/SymfonyStyle.php +++ b/Style/SymfonyStyle.php @@ -79,8 +79,8 @@ public function title(string $message) { $this->autoPrependBlock(); $this->writeln([ - sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), - sprintf('%s', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), + \sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), + \sprintf('%s', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), ]); $this->newLine(); } @@ -92,8 +92,8 @@ public function section(string $message) { $this->autoPrependBlock(); $this->writeln([ - sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), - sprintf('%s', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), + \sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), + \sprintf('%s', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), ]); $this->newLine(); } @@ -104,7 +104,7 @@ public function section(string $message) public function listing(array $elements) { $this->autoPrependText(); - $elements = array_map(fn ($element) => sprintf(' * %s', $element), $elements); + $elements = array_map(fn ($element) => \sprintf(' * %s', $element), $elements); $this->writeln($elements); $this->newLine(); @@ -119,7 +119,7 @@ public function text(string|array $message) $messages = \is_array($message) ? array_values($message) : [$message]; foreach ($messages as $message) { - $this->writeln(sprintf(' %s', $message)); + $this->writeln(\sprintf(' %s', $message)); } } @@ -463,7 +463,7 @@ private function createBlock(iterable $messages, ?string $type = null, ?string $ $lines = []; if (null !== $type) { - $type = sprintf('[%s] ', $type); + $type = \sprintf('[%s] ', $type); $indentLength = Helper::width($type); $lineIndentation = str_repeat(' ', $indentLength); } @@ -505,7 +505,7 @@ private function createBlock(iterable $messages, ?string $type = null, ?string $ $line .= str_repeat(' ', max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0)); if ($style) { - $line = sprintf('<%s>%s', $style, $line); + $line = \sprintf('<%s>%s', $style, $line); } } diff --git a/Tester/Constraint/CommandIsSuccessful.php b/Tester/Constraint/CommandIsSuccessful.php index 09c6194b9..d677c27aa 100644 --- a/Tester/Constraint/CommandIsSuccessful.php +++ b/Tester/Constraint/CommandIsSuccessful.php @@ -38,6 +38,6 @@ protected function additionalFailureDescription($other): string Command::INVALID => 'Command was invalid.', ]; - return $mapping[$other] ?? sprintf('Command returned exit status %d.', $other); + return $mapping[$other] ?? \sprintf('Command returned exit status %d.', $other); } } diff --git a/Tests/ApplicationTest.php b/Tests/ApplicationTest.php index ac1d47245..a1884ff31 100644 --- a/Tests/ApplicationTest.php +++ b/Tests/ApplicationTest.php @@ -635,7 +635,7 @@ public function testFindAlternativeCommands() } catch (\Exception $e) { $this->assertInstanceOf(CommandNotFoundException::class, $e, '->find() throws a CommandNotFoundException if command does not exist'); $this->assertSame([], $e->getAlternatives()); - $this->assertEquals(sprintf('Command "%s" is not defined.', $commandName), $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, without alternatives'); + $this->assertEquals(\sprintf('Command "%s" is not defined.', $commandName), $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, without alternatives'); } // Test if "bar1" command throw a "CommandNotFoundException" and does not contain @@ -646,7 +646,7 @@ public function testFindAlternativeCommands() } catch (\Exception $e) { $this->assertInstanceOf(CommandNotFoundException::class, $e, '->find() throws a CommandNotFoundException if command does not exist'); $this->assertSame(['afoobar1', 'foo:bar1'], $e->getAlternatives()); - $this->assertMatchesRegularExpression(sprintf('/Command "%s" is not defined./', $commandName), $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives'); + $this->assertMatchesRegularExpression(\sprintf('/Command "%s" is not defined./', $commandName), $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives'); $this->assertMatchesRegularExpression('/afoobar1/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternative : "afoobar1"'); $this->assertMatchesRegularExpression('/foo:bar1/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternative : "foo:bar1"'); $this->assertDoesNotMatchRegularExpression('/foo:bar(?!1)/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, without "foo:bar" alternative'); @@ -965,7 +965,7 @@ public function testRenderAnonymousException() $application = new Application(); $application->setAutoExit(false); $application->register('foo')->setCode(function () { - throw new \InvalidArgumentException(sprintf('Dummy type "%s" is invalid.', (new class() {})::class)); + throw new \InvalidArgumentException(\sprintf('Dummy type "%s" is invalid.', (new class {})::class)); }); $tester = new ApplicationTester($application); @@ -991,7 +991,7 @@ public function testRenderExceptionStackTraceContainsRootException() $application = new Application(); $application->setAutoExit(false); $application->register('foo')->setCode(function () { - throw new \InvalidArgumentException(sprintf('Dummy type "%s" is invalid.', (new class() {})::class)); + throw new \InvalidArgumentException(\sprintf('Dummy type "%s" is invalid.', (new class {})::class)); }); $tester = new ApplicationTester($application); diff --git a/Tests/Command/CommandTest.php b/Tests/Command/CommandTest.php index 76dacfadb..58fbfcf79 100644 --- a/Tests/Command/CommandTest.php +++ b/Tests/Command/CommandTest.php @@ -142,7 +142,7 @@ public function testGetNamespaceGetNameSetName() public function testInvalidCommandNames($name) { $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage(sprintf('Command name "%s" is invalid.', $name)); + $this->expectExceptionMessage(\sprintf('Command name "%s" is invalid.', $name)); (new \TestCommand())->setName($name); } diff --git a/Tests/Command/SingleCommandApplicationTest.php b/Tests/Command/SingleCommandApplicationTest.php index 8fae4876b..98000c0a7 100644 --- a/Tests/Command/SingleCommandApplicationTest.php +++ b/Tests/Command/SingleCommandApplicationTest.php @@ -21,7 +21,7 @@ class SingleCommandApplicationTest extends TestCase { public function testRun() { - $command = new class() extends SingleCommandApplication { + $command = new class extends SingleCommandApplication { protected function execute(InputInterface $input, OutputInterface $output): int { return 0; diff --git a/Tests/Descriptor/AbstractDescriptorTestCase.php b/Tests/Descriptor/AbstractDescriptorTestCase.php index 1f813048d..93658f4be 100644 --- a/Tests/Descriptor/AbstractDescriptorTestCase.php +++ b/Tests/Descriptor/AbstractDescriptorTestCase.php @@ -87,7 +87,7 @@ protected static function getDescriptionTestData(array $objects) { $data = []; foreach ($objects as $name => $object) { - $description = file_get_contents(sprintf('%s/../Fixtures/%s.%s', __DIR__, $name, static::getFormat())); + $description = file_get_contents(\sprintf('%s/../Fixtures/%s.%s', __DIR__, $name, static::getFormat())); $data[] = [$object, $description]; } diff --git a/Tests/Helper/ProgressBarTest.php b/Tests/Helper/ProgressBarTest.php index 615237f1f..af7cf2ef5 100644 --- a/Tests/Helper/ProgressBarTest.php +++ b/Tests/Helper/ProgressBarTest.php @@ -423,7 +423,7 @@ public function testOverwriteWithSectionOutputAndEol() $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter()); $bar = new ProgressBar($output, 50, 0); - $bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '%message%' . PHP_EOL); + $bar->setFormat('[%bar%] %percent:3s%%'.\PHP_EOL.'%message%'.\PHP_EOL); $bar->setMessage(''); $bar->start(); $bar->display(); @@ -435,8 +435,8 @@ public function testOverwriteWithSectionOutputAndEol() rewind($output->getStream()); $this->assertEquals(escapeshellcmd( '[>---------------------------] 0%'.\PHP_EOL.\PHP_EOL. - "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL. 'Doing something...' . \PHP_EOL . - "\x1b[2A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL. 'Doing something foo...' . \PHP_EOL), + "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL.'Doing something...'.\PHP_EOL. + "\x1b[2A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL.'Doing something foo...'.\PHP_EOL), escapeshellcmd(stream_get_contents($output->getStream())) ); } @@ -448,7 +448,7 @@ public function testOverwriteWithSectionOutputAndEolWithEmptyMessage() $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter()); $bar = new ProgressBar($output, 50, 0); - $bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '%message%'); + $bar->setFormat('[%bar%] %percent:3s%%'.\PHP_EOL.'%message%'); $bar->setMessage('Start'); $bar->start(); $bar->display(); @@ -460,8 +460,8 @@ public function testOverwriteWithSectionOutputAndEolWithEmptyMessage() rewind($output->getStream()); $this->assertEquals(escapeshellcmd( '[>---------------------------] 0%'.\PHP_EOL.'Start'.\PHP_EOL. - "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL . - "\x1b[1A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL. 'Doing something...' . \PHP_EOL), + "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL. + "\x1b[1A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL.'Doing something...'.\PHP_EOL), escapeshellcmd(stream_get_contents($output->getStream())) ); } @@ -473,7 +473,7 @@ public function testOverwriteWithSectionOutputAndEolWithEmptyMessageComment() $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter()); $bar = new ProgressBar($output, 50, 0); - $bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '%message%'); + $bar->setFormat('[%bar%] %percent:3s%%'.\PHP_EOL.'%message%'); $bar->setMessage('Start'); $bar->start(); $bar->display(); @@ -485,8 +485,8 @@ public function testOverwriteWithSectionOutputAndEolWithEmptyMessageComment() rewind($output->getStream()); $this->assertEquals(escapeshellcmd( '[>---------------------------] 0%'.\PHP_EOL."\x1b[33mStart\x1b[39m".\PHP_EOL. - "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL . - "\x1b[1A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL. "\x1b[33mDoing something...\x1b[39m" . \PHP_EOL), + "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL. + "\x1b[1A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL."\x1b[33mDoing something...\x1b[39m".\PHP_EOL), escapeshellcmd(stream_get_contents($output->getStream())) ); } diff --git a/Tests/Helper/ProgressIndicatorTest.php b/Tests/Helper/ProgressIndicatorTest.php index 7f7dbc0a0..8e2e10e37 100644 --- a/Tests/Helper/ProgressIndicatorTest.php +++ b/Tests/Helper/ProgressIndicatorTest.php @@ -179,6 +179,6 @@ protected function generateOutput($expected) { $count = substr_count($expected, "\n"); - return "\x0D\x1B[2K".($count ? sprintf("\033[%dA", $count) : '').$expected; + return "\x0D\x1B[2K".($count ? \sprintf("\033[%dA", $count) : '').$expected; } } diff --git a/Tests/Helper/TableTest.php b/Tests/Helper/TableTest.php index bb1b96346..ebdfa5a5d 100644 --- a/Tests/Helper/TableTest.php +++ b/Tests/Helper/TableTest.php @@ -112,7 +112,7 @@ public static function renderProvider() | 80-902734-1-6 | And Then There Were None | Agatha Christie | +---------------+--------------------------+------------------+ -TABLE +TABLE, ], [ ['ISBN', 'Title', 'Author'], @@ -157,7 +157,7 @@ public static function renderProvider() │ 80-902734-1-6 │ And Then There Were None │ Agatha Christie │ └───────────────┴──────────────────────────┴──────────────────┘ -TABLE +TABLE, ], [ ['ISBN', 'Title', 'Author'], @@ -180,7 +180,7 @@ public static function renderProvider() ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ ╚═══════════════╧══════════════════════════╧══════════════════╝ -TABLE +TABLE, ], [ ['ISBN', 'Title'], @@ -201,7 +201,7 @@ public static function renderProvider() | 80-902734-1-6 | And Then There Were None | Agatha Christie | +---------------+--------------------------+------------------+ -TABLE +TABLE, ], [ [], @@ -220,7 +220,7 @@ public static function renderProvider() | 80-902734-1-6 | And Then There Were None | Agatha Christie | +---------------+--------------------------+------------------+ -TABLE +TABLE, ], [ ['ISBN', 'Title', 'Author'], @@ -245,7 +245,7 @@ public static function renderProvider() | | | Tolkien | +---------------+----------------------------+-----------------+ -TABLE +TABLE, ], [ ['ISBN', 'Title'], @@ -256,7 +256,7 @@ public static function renderProvider() | ISBN | Title | +------+-------+ -TABLE +TABLE, ], [ [], @@ -279,7 +279,7 @@ public static function renderProvider() | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | +---------------+----------------------+-----------------+ -TABLE +TABLE, ], 'Cell text with tags not used for Output styling' => [ ['ISBN', 'Title', 'Author'], @@ -296,7 +296,7 @@ public static function renderProvider() | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | +----------------------------------+----------------------+-----------------+ -TABLE +TABLE, ], 'Cell with colspan' => [ ['ISBN', 'Title', 'Author'], @@ -336,7 +336,7 @@ public static function renderProvider() | Cupìdĭtâte díctá âtquè pôrrò, tèmpórà exercitátìónèm mòdí ânìmí núllà nèmò vèl níhìl! | +-------------------------------+-------------------------------+-----------------------------+ -TABLE +TABLE, ], 'Cell after colspan contains new line break' => [ ['Foo', 'Bar', 'Baz'], @@ -355,7 +355,7 @@ public static function renderProvider() | bar | qux | +-----+-----+-----+ -TABLE +TABLE, ], 'Cell after colspan contains multiple new lines' => [ ['Foo', 'Bar', 'Baz'], @@ -375,7 +375,7 @@ public static function renderProvider() | | quux | +-----+-----+------+ -TABLE +TABLE, ], 'Cell with rowspan' => [ ['ISBN', 'Title', 'Author'], @@ -406,7 +406,7 @@ public static function renderProvider() | | Were None | | +---------------+---------------+-----------------+ -TABLE +TABLE, ], 'Cell with rowspan and colspan' => [ ['ISBN', 'Title', 'Author'], @@ -437,7 +437,7 @@ public static function renderProvider() | J. R. R | | +------------------+---------+-----------------+ -TABLE +TABLE, ], 'Cell with rowspan and colspan contains new line break' => [ ['ISBN', 'Title', 'Author'], @@ -480,7 +480,7 @@ public static function renderProvider() | 0-0 | | +-----------------+-------+-----------------+ -TABLE +TABLE, ], 'Cell with rowspan and colspan without using TableSeparator' => [ ['ISBN', 'Title', 'Author'], @@ -511,7 +511,7 @@ public static function renderProvider() | | 0-0 | +-----------------+-------+-----------------+ -TABLE +TABLE, ], 'Cell with rowspan and colspan with separator inside a rowspan' => [ ['ISBN', 'Author'], @@ -533,7 +533,7 @@ public static function renderProvider() | | Charles Dickens | +---------------+-----------------+ -TABLE +TABLE, ], 'Multiple header lines' => [ [ @@ -549,7 +549,7 @@ public static function renderProvider() | ISBN | Title | Author | +------+-------+--------+ -TABLE +TABLE, ], 'Row with multiple cells' => [ [], @@ -567,7 +567,7 @@ public static function renderProvider() | 1 | 2 | 3 | 4 | +---+--+--+---+--+---+--+---+--+ -TABLE +TABLE, ], 'Coslpan and table cells with comment style' => [ [ @@ -1305,7 +1305,7 @@ public static function renderSetTitle() | 80-902734-1-6 | And Then There Were None | Agatha Christie | +---------------+---------- footer --------+------------------+ -TABLE +TABLE, ], [ 'Books', @@ -1321,7 +1321,7 @@ public static function renderSetTitle() │ 80-902734-1-6 │ And Then There Were None │ Agatha Christie │ └───────────────┴───────── Page 1/2 ───────┴──────────────────┘ -TABLE +TABLE, ], [ 'Boooooooooooooooooooooooooooooooooooooooooooooooooooooooks', @@ -1337,7 +1337,7 @@ public static function renderSetTitle() | 80-902734-1-6 | And Then There Were None | Agatha Christie | +- Page 1/99999999999999999999999999999999999999999999999... -+ -TABLE +TABLE, ], ]; } @@ -2085,12 +2085,12 @@ public function testGithubIssue60038WidthOfCellWithEmoji() ->setHeaderTitle('Test Title') ->setHeaders(['Title', 'Author']) ->setRows([ - ["🎭 💫 ☯"." Divine Comedy", "Dante Alighieri"], + ['🎭 💫 ☯ Divine Comedy', 'Dante Alighieri'], // the snowflake (e2 9d 84 ef b8 8f) has a variant selector - ["👑 ❄️ 🗡"." Game of Thrones", "George R.R. Martin"], + ['👑 ❄️ 🗡 Game of Thrones', 'George R.R. Martin'], // the snowflake in text style (e2 9d 84 ef b8 8e) has a variant selector - ["❄︎❄︎❄︎ snowflake in text style ❄︎❄︎❄︎", ""], - ["And a very long line to show difference in previous lines", ""], + ['❄︎❄︎❄︎ snowflake in text style ❄︎❄︎❄︎', ''], + ['And a very long line to show difference in previous lines', ''], ]) ; $table->render(); diff --git a/Tests/Input/InputDefinitionTest.php b/Tests/Input/InputDefinitionTest.php index 470f3ca74..137834655 100644 --- a/Tests/Input/InputDefinitionTest.php +++ b/Tests/Input/InputDefinitionTest.php @@ -113,7 +113,7 @@ public function testRequiredArgumentCannotFollowAnOptionalOne() { $this->initializeArguments(); $this->expectException(\LogicException::class); - $this->expectExceptionMessage(sprintf('Cannot add a required argument "%s" after an optional one "%s".', $this->foo2->getName(), $this->foo->getName())); + $this->expectExceptionMessage(\sprintf('Cannot add a required argument "%s" after an optional one "%s".', $this->foo2->getName(), $this->foo->getName())); $definition = new InputDefinition(); $definition->addArgument($this->foo); @@ -179,7 +179,7 @@ public function testGetArgumentDefaults() new InputArgument('foo1', InputArgument::OPTIONAL), new InputArgument('foo2', InputArgument::OPTIONAL, '', 'default'), new InputArgument('foo3', InputArgument::OPTIONAL | InputArgument::IS_ARRAY), - // new InputArgument('foo4', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, '', [1, 2]), + // new InputArgument('foo4', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, '', [1, 2]), ]); $this->assertEquals(['foo1' => null, 'foo2' => 'default', 'foo3' => []], $definition->getArgumentDefaults(), '->getArgumentDefaults() return the default values for each argument'); diff --git a/Tests/Messenger/RunCommandMessageHandlerTest.php b/Tests/Messenger/RunCommandMessageHandlerTest.php index 3d8e3e195..898492374 100644 --- a/Tests/Messenger/RunCommandMessageHandlerTest.php +++ b/Tests/Messenger/RunCommandMessageHandlerTest.php @@ -122,7 +122,7 @@ private function createApplicationWithCommand(): Application $application = new Application(); $application->setAutoExit(false); $application->addCommands([ - new class() extends Command { + new class extends Command { public function configure(): void { $this diff --git a/Tests/Output/ConsoleSectionOutputTest.php b/Tests/Output/ConsoleSectionOutputTest.php index e50f8d54a..6d2fa6c3c 100644 --- a/Tests/Output/ConsoleSectionOutputTest.php +++ b/Tests/Output/ConsoleSectionOutputTest.php @@ -44,7 +44,7 @@ public function testClearAll() $output->clear(); rewind($output->getStream()); - $this->assertEquals('Foo'.\PHP_EOL.'Bar'.\PHP_EOL.sprintf("\x1b[%dA", 2)."\x1b[0J", stream_get_contents($output->getStream())); + $this->assertEquals('Foo'.\PHP_EOL.'Bar'.\PHP_EOL.\sprintf("\x1b[%dA", 2)."\x1b[0J", stream_get_contents($output->getStream())); } public function testClearNumberOfLines() @@ -56,7 +56,7 @@ public function testClearNumberOfLines() $output->clear(2); rewind($output->getStream()); - $this->assertEquals("Foo\nBar\nBaz\nFooBar".\PHP_EOL.sprintf("\x1b[%dA", 2)."\x1b[0J", stream_get_contents($output->getStream())); + $this->assertEquals("Foo\nBar\nBaz\nFooBar".\PHP_EOL.\sprintf("\x1b[%dA", 2)."\x1b[0J", stream_get_contents($output->getStream())); } public function testClearNumberOfLinesWithMultipleSections() @@ -197,7 +197,7 @@ public function testOverwriteMultipleLines() $output->overwrite('Bar'); rewind($output->getStream()); - $this->assertEquals('Foo'.\PHP_EOL.'Bar'.\PHP_EOL.'Baz'.\PHP_EOL.sprintf("\x1b[%dA", 3)."\x1b[0J".'Bar'.\PHP_EOL, stream_get_contents($output->getStream())); + $this->assertEquals('Foo'.\PHP_EOL.'Bar'.\PHP_EOL.'Baz'.\PHP_EOL.\sprintf("\x1b[%dA", 3)."\x1b[0J".'Bar'.\PHP_EOL, stream_get_contents($output->getStream())); } public function testAddingMultipleSections() diff --git a/Tests/Question/ConfirmationQuestionTest.php b/Tests/Question/ConfirmationQuestionTest.php index 44f4c870b..bd11047b3 100644 --- a/Tests/Question/ConfirmationQuestionTest.php +++ b/Tests/Question/ConfirmationQuestionTest.php @@ -26,7 +26,7 @@ public function testDefaultRegexUsecases($default, $answers, $expected, $message foreach ($answers as $answer) { $normalizer = $sut->getNormalizer(); $actual = $normalizer($answer); - $this->assertEquals($expected, $actual, sprintf($message, $answer)); + $this->assertEquals($expected, $actual, \sprintf($message, $answer)); } } From 4ea291e80c6eafe7396dbcbd7ef6fe07350db134 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 12 Jul 2025 11:35:41 +0200 Subject: [PATCH 3/8] Fix @var phpdoc --- Tests/Formatter/OutputFormatterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Formatter/OutputFormatterTest.php b/Tests/Formatter/OutputFormatterTest.php index 477f1bdf6..eb8e483f3 100644 --- a/Tests/Formatter/OutputFormatterTest.php +++ b/Tests/Formatter/OutputFormatterTest.php @@ -177,7 +177,7 @@ public function testInlineStyleOptions(string $tag, ?string $expected = null, ?s $expected = $tag.$input.''; $this->assertSame($expected, $formatter->format($expected)); } else { - /* @var OutputFormatterStyle $result */ + /** @var OutputFormatterStyle $result */ $this->assertInstanceOf(OutputFormatterStyle::class, $result); $this->assertSame($expected, $formatter->format($tag.$input.'')); $this->assertSame($expected, $formatter->format($tag.$input.'')); From f987f3c37dfe7e0b8103bc5f4d5f94e874efa7f1 Mon Sep 17 00:00:00 2001 From: Vincent Amstoutz Date: Wed, 16 Jul 2025 13:56:50 +0200 Subject: [PATCH 4/8] [Console] fix profiler with overridden `run()` method --- Command/TraceableCommand.php | 2 +- Tests/Command/TraceableCommandTest.php | 66 ++++++++++++++++++++++++++ Tests/Fixtures/AbstractLoopCommand.php | 41 ++++++++++++++++ Tests/Fixtures/LoopExampleCommand.php | 28 +++++++++++ 4 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 Tests/Command/TraceableCommandTest.php create mode 100644 Tests/Fixtures/AbstractLoopCommand.php create mode 100644 Tests/Fixtures/LoopExampleCommand.php diff --git a/Command/TraceableCommand.php b/Command/TraceableCommand.php index 9ffb68da3..9df467b0d 100644 --- a/Command/TraceableCommand.php +++ b/Command/TraceableCommand.php @@ -283,7 +283,7 @@ public function run(InputInterface $input, OutputInterface $output): int $event = $this->stopwatch->start($this->getName(), 'command'); try { - $this->exitCode = parent::run($input, $output); + $this->exitCode = $this->command->run($input, $output); } finally { $event->stop(); diff --git a/Tests/Command/TraceableCommandTest.php b/Tests/Command/TraceableCommandTest.php new file mode 100644 index 000000000..2775ec7e9 --- /dev/null +++ b/Tests/Command/TraceableCommandTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Command; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\TraceableCommand; +use Symfony\Component\Console\Tester\CommandTester; +use Symfony\Component\Console\Tests\Fixtures\LoopExampleCommand; +use Symfony\Component\Stopwatch\Stopwatch; + +class TraceableCommandTest extends TestCase +{ + private Application $application; + + protected function setUp(): void + { + $this->application = new Application(); + $this->application->add(new LoopExampleCommand()); + } + + public function testRunIsOverriddenWithoutProfile() + { + $command = $this->application->find('app:loop:example'); + $commandTester = new CommandTester($command); + $commandTester->execute([]); + $commandTester->assertCommandIsSuccessful(); + + $output = $commandTester->getDisplay(); + $this->assertLoopOutputCorrectness($output); + } + + public function testRunIsNotOverriddenWithProfile() + { + // Simulate the bug environment by wrapping + // our command in TraceableCommand, which is what Symfony does + // when you use the --profile option. + $command = new LoopExampleCommand(); + $traceableCommand = new TraceableCommand($command, new Stopwatch()); + + $this->application->add($traceableCommand); + + $commandTester = new CommandTester($traceableCommand); + $commandTester->execute([]); + $commandTester->assertCommandIsSuccessful(); + + $output = $commandTester->getDisplay(); + $this->assertLoopOutputCorrectness($output); + } + + public function assertLoopOutputCorrectness(string $output) + { + self::assertMatchesRegularExpression('~3/3\s+\[▓+]\s+100%~u', $output); + self::assertStringContainsString('Loop finished.', $output); + self::assertEquals(3, substr_count($output, 'Hello world')); + } +} diff --git a/Tests/Fixtures/AbstractLoopCommand.php b/Tests/Fixtures/AbstractLoopCommand.php new file mode 100644 index 000000000..c3715067e --- /dev/null +++ b/Tests/Fixtures/AbstractLoopCommand.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Fixtures; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +abstract class AbstractLoopCommand extends Command +{ + public function run(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + $contexts = [1, 2, 3]; + $io->progressStart(count($contexts)); + $code = self::SUCCESS; + + foreach ($contexts as $ignored) { + $io->progressAdvance(); + try { + parent::run($input, $output); + } catch (\Throwable) { + $code = self::FAILURE; + } + } + $io->progressFinish(); + $output->writeln("\nLoop finished."); + + return $code; + } +} diff --git a/Tests/Fixtures/LoopExampleCommand.php b/Tests/Fixtures/LoopExampleCommand.php new file mode 100644 index 000000000..d9eeb4db9 --- /dev/null +++ b/Tests/Fixtures/LoopExampleCommand.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Fixtures; + +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +#[AsCommand('app:loop:example')] +class LoopExampleCommand extends AbstractLoopCommand +{ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $output->writeln(' Hello world'); + + return Command::SUCCESS; + } +} From 9fb3320d4ff66529273078cacb02e948deff4647 Mon Sep 17 00:00:00 2001 From: eltharin Date: Sun, 20 Jul 2025 13:48:03 +0200 Subject: [PATCH 5/8] [Console] Windows Test Error - change completecar for windows for passing test --- Tests/Command/TraceableCommandTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/Command/TraceableCommandTest.php b/Tests/Command/TraceableCommandTest.php index 2775ec7e9..1bf709f8b 100644 --- a/Tests/Command/TraceableCommandTest.php +++ b/Tests/Command/TraceableCommandTest.php @@ -59,7 +59,8 @@ public function testRunIsNotOverriddenWithProfile() public function assertLoopOutputCorrectness(string $output) { - self::assertMatchesRegularExpression('~3/3\s+\[▓+]\s+100%~u', $output); + $completeChar = '\\' !== \DIRECTORY_SEPARATOR ? '▓' : '='; + self::assertMatchesRegularExpression('~3/3\s+\['.$completeChar.'+]\s+100%~u', $output); self::assertStringContainsString('Loop finished.', $output); self::assertEquals(3, substr_count($output, 'Hello world')); } From 795dd192e797631c54b78952843aacdbe9b4445e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 22 Jul 2025 14:33:39 +0200 Subject: [PATCH 6/8] [Console] Fix JSON description for negatable input flags --- Descriptor/JsonDescriptor.php | 2 +- Tests/Descriptor/JsonDescriptorTest.php | 9 ++++----- Tests/Fixtures/application_2.json | 16 ++++++++-------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Descriptor/JsonDescriptor.php b/Descriptor/JsonDescriptor.php index 956303709..9a8e696cd 100644 --- a/Descriptor/JsonDescriptor.php +++ b/Descriptor/JsonDescriptor.php @@ -108,7 +108,7 @@ private function getInputOptionData(InputOption $option, bool $negated = false): 'is_value_required' => false, 'is_multiple' => false, 'description' => 'Negate the "--'.$option->getName().'" option', - 'default' => false, + 'default' => null === $option->getDefault() ? null : !$option->getDefault(), ] : [ 'name' => '--'.$option->getName(), 'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '', diff --git a/Tests/Descriptor/JsonDescriptorTest.php b/Tests/Descriptor/JsonDescriptorTest.php index 399bd8f23..914ed3597 100644 --- a/Tests/Descriptor/JsonDescriptorTest.php +++ b/Tests/Descriptor/JsonDescriptorTest.php @@ -36,10 +36,9 @@ private function normalizeOutputRecursively($output) return array_map($this->normalizeOutputRecursively(...), $output); } - if (null === $output) { - return null; - } - - return parent::normalizeOutput($output); + return match ($output) { + null, true, false => $output, + default => parent::normalizeOutput($output), + }; } } diff --git a/Tests/Fixtures/application_2.json b/Tests/Fixtures/application_2.json index b3eb10bda..33a90e356 100644 --- a/Tests/Fixtures/application_2.json +++ b/Tests/Fixtures/application_2.json @@ -85,7 +85,7 @@ "is_value_required": false, "is_multiple": false, "description": "Do not ask any interactive question", - "default": false + "default": null }, "shell": { "name": "--shell", @@ -206,7 +206,7 @@ "is_value_required": false, "is_multiple": false, "description": "Do not ask any interactive question", - "default": false + "default": null }, "debug": { "name": "--debug", @@ -318,7 +318,7 @@ "is_value_required": false, "is_multiple": false, "description": "Do not ask any interactive question", - "default": false + "default": null } } } @@ -421,7 +421,7 @@ "is_value_required": false, "is_multiple": false, "description": "Do not ask any interactive question", - "default": false + "default": null }, "short": { "name": "--short", @@ -509,7 +509,7 @@ "is_value_required": false, "is_multiple": false, "description": "Do not ask any interactive question", - "default": false + "default": null } } } @@ -605,7 +605,7 @@ "is_value_required": false, "is_multiple": false, "description": "Do not ask any interactive question", - "default": false + "default": null } } } @@ -682,7 +682,7 @@ "is_value_required": false, "is_multiple": false, "description": "Do not ask any interactive question", - "default": false + "default": null } } } @@ -761,7 +761,7 @@ "is_value_required": false, "is_multiple": false, "description": "Do not ask any interactive question", - "default": false + "default": null } } } From e8ebdeeeda075f5074ffca383d48599317de7b8b Mon Sep 17 00:00:00 2001 From: schlndh Date: Sat, 26 Jul 2025 10:03:12 +0200 Subject: [PATCH 7/8] [Console][Table] Fix invalid UTF-8 due to text wrapping Fixes #58286 --- Formatter/OutputFormatter.php | 15 +++++++++------ Helper/Helper.php | 4 ++++ Tests/Formatter/OutputFormatterTest.php | 4 ++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Formatter/OutputFormatter.php b/Formatter/OutputFormatter.php index 52d831620..15c14b6d8 100644 --- a/Formatter/OutputFormatter.php +++ b/Formatter/OutputFormatter.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Console\Formatter; use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Helper\Helper; use function Symfony\Component\String\b; @@ -146,9 +147,11 @@ public function formatAndWrap(?string $message, int $width) continue; } + // convert byte position to character position. + $pos = Helper::length(substr($message, 0, $pos)); // add the text up to the next tag - $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength); - $offset = $pos + \strlen($text); + $output .= $this->applyCurrentStyle(Helper::substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength); + $offset = $pos + Helper::length($text); // opening tag? if ($open = '/' !== $text[1]) { @@ -169,7 +172,7 @@ public function formatAndWrap(?string $message, int $width) } } - $output .= $this->applyCurrentStyle(substr($message, $offset), $output, $width, $currentLineLength); + $output .= $this->applyCurrentStyle(Helper::substr($message, $offset), $output, $width, $currentLineLength); return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']); } @@ -236,8 +239,8 @@ private function applyCurrentStyle(string $text, string $current, int $width, in } if ($currentLineLength) { - $prefix = substr($text, 0, $i = $width - $currentLineLength)."\n"; - $text = substr($text, $i); + $prefix = Helper::substr($text, 0, $i = $width - $currentLineLength)."\n"; + $text = Helper::substr($text, $i); } else { $prefix = ''; } @@ -253,7 +256,7 @@ private function applyCurrentStyle(string $text, string $current, int $width, in $lines = explode("\n", $text); foreach ($lines as $line) { - $currentLineLength += \strlen($line); + $currentLineLength += Helper::length($line); if ($width <= $currentLineLength) { $currentLineLength = 0; } diff --git a/Helper/Helper.php b/Helper/Helper.php index eec328498..468d06689 100644 --- a/Helper/Helper.php +++ b/Helper/Helper.php @@ -86,6 +86,10 @@ public static function substr(?string $string, int $from, ?int $length = null): { $string ??= ''; + if (preg_match('//u', $string)) { + return (new UnicodeString($string))->slice($from, $length); + } + if (false === $encoding = mb_detect_encoding($string, null, true)) { return substr($string, $from, $length); } diff --git a/Tests/Formatter/OutputFormatterTest.php b/Tests/Formatter/OutputFormatterTest.php index eb8e483f3..4dbeb702d 100644 --- a/Tests/Formatter/OutputFormatterTest.php +++ b/Tests/Formatter/OutputFormatterTest.php @@ -365,6 +365,8 @@ public function testFormatAndWrap() $this->assertSame("Lore\nm \e[37;41mip\e[39;49m\n\e[37;41msum\e[39;49m \ndolo\nr \e[32msi\e[39m\n\e[32mt\e[39m am\net", $formatter->formatAndWrap('Lorem ipsum dolor sit amet', 4)); $this->assertSame("Lorem \e[37;41mip\e[39;49m\n\e[37;41msum\e[39;49m dolo\nr \e[32msit\e[39m am\net", $formatter->formatAndWrap('Lorem ipsum dolor sit amet', 8)); $this->assertSame("Lorem \e[37;41mipsum\e[39;49m dolor \e[32m\e[39m\n\e[32msit\e[39m, \e[37;41mamet\e[39;49m et \e[32mlauda\e[39m\n\e[32mntium\e[39m architecto", $formatter->formatAndWrap('Lorem ipsum dolor sit, amet et laudantium architecto', 18)); + $this->assertSame("\e[37;41mnon-empty-array\e[39;49m\e[37;41m\e[39;49m given.\n🪪\n argument.type", $formatter->formatAndWrap("non-empty-array given.\n🪪 argument.type", 38)); + $this->assertSame("Usuário {{user_name}} não é válid\no.", $formatter->formatAndWrap('Usuário {{user_name}} não é válido.', 50)); $formatter = new OutputFormatter(); @@ -376,6 +378,8 @@ public function testFormatAndWrap() $this->assertSame("Â rèälly\nlöng tîtlè\nthät cöüld\nnèêd\nmúltîplê\nlínès", $formatter->formatAndWrap('Â rèälly löng tîtlè thät cöüld nèêd múltîplê línès', 10)); $this->assertSame("Â rèälly\nlöng tîtlè\nthät cöüld\nnèêd\nmúltîplê\n línès", $formatter->formatAndWrap("Â rèälly löng tîtlè thät cöüld nèêd múltîplê\n línès", 10)); $this->assertSame('', $formatter->formatAndWrap(null, 5)); + $this->assertSame("non-empty-array given.\n🪪\n argument.type", $formatter->formatAndWrap("non-empty-array given.\n🪪 argument.type", 38)); + $this->assertSame("Usuário {{user_name}} não é válid\no.", $formatter->formatAndWrap('Usuário {{user_name}} não é válido.', 50)); } } From 59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350 Mon Sep 17 00:00:00 2001 From: schlndh Date: Sun, 27 Jul 2025 14:31:02 +0200 Subject: [PATCH 8/8] [Console][Table] Fix unnecessary wrapping --- Formatter/OutputFormatter.php | 18 ++++++++++++++---- Tests/Formatter/OutputFormatterTest.php | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Formatter/OutputFormatter.php b/Formatter/OutputFormatter.php index 15c14b6d8..c37a4d452 100644 --- a/Formatter/OutputFormatter.php +++ b/Formatter/OutputFormatter.php @@ -239,8 +239,18 @@ private function applyCurrentStyle(string $text, string $current, int $width, in } if ($currentLineLength) { - $prefix = Helper::substr($text, 0, $i = $width - $currentLineLength)."\n"; - $text = Helper::substr($text, $i); + $lines = explode("\n", $text, 2); + $prefix = Helper::substr($lines[0], 0, $i = $width - $currentLineLength)."\n"; + $text = Helper::substr($lines[0], $i); + + if (isset($lines[1])) { + // $prefix may contain the full first line in which the \n is already a part of $prefix. + if ('' !== $text) { + $text .= "\n"; + } + + $text .= $lines[1]; + } } else { $prefix = ''; } @@ -255,8 +265,8 @@ private function applyCurrentStyle(string $text, string $current, int $width, in $lines = explode("\n", $text); - foreach ($lines as $line) { - $currentLineLength += Helper::length($line); + foreach ($lines as $i => $line) { + $currentLineLength = 0 === $i ? $currentLineLength + Helper::length($line) : Helper::length($line); if ($width <= $currentLineLength) { $currentLineLength = 0; } diff --git a/Tests/Formatter/OutputFormatterTest.php b/Tests/Formatter/OutputFormatterTest.php index 4dbeb702d..b66b6abe4 100644 --- a/Tests/Formatter/OutputFormatterTest.php +++ b/Tests/Formatter/OutputFormatterTest.php @@ -365,8 +365,14 @@ public function testFormatAndWrap() $this->assertSame("Lore\nm \e[37;41mip\e[39;49m\n\e[37;41msum\e[39;49m \ndolo\nr \e[32msi\e[39m\n\e[32mt\e[39m am\net", $formatter->formatAndWrap('Lorem ipsum dolor sit amet', 4)); $this->assertSame("Lorem \e[37;41mip\e[39;49m\n\e[37;41msum\e[39;49m dolo\nr \e[32msit\e[39m am\net", $formatter->formatAndWrap('Lorem ipsum dolor sit amet', 8)); $this->assertSame("Lorem \e[37;41mipsum\e[39;49m dolor \e[32m\e[39m\n\e[32msit\e[39m, \e[37;41mamet\e[39;49m et \e[32mlauda\e[39m\n\e[32mntium\e[39m architecto", $formatter->formatAndWrap('Lorem ipsum dolor sit, amet et laudantium architecto', 18)); - $this->assertSame("\e[37;41mnon-empty-array\e[39;49m\e[37;41m\e[39;49m given.\n🪪\n argument.type", $formatter->formatAndWrap("non-empty-array given.\n🪪 argument.type", 38)); + $this->assertSame("\e[37;41mnon-empty-array\e[39;49m\e[37;41m\e[39;49m given.\n🪪 argument.type", $formatter->formatAndWrap("non-empty-array given.\n🪪 argument.type", 38)); $this->assertSame("Usuário {{user_name}} não é válid\no.", $formatter->formatAndWrap('Usuário {{user_name}} não é válido.', 50)); + $this->assertSame("foo\e[37;41mb\e[39;49m\n\e[37;41mar\e[39;49mbaz", $formatter->formatAndWrap("foob\narbaz", 7)); + $this->assertSame("foo\e[37;41mbar\e[39;49mbaz\nnewline", $formatter->formatAndWrap("foobarbaz\nnewline", 11)); + $this->assertSame("foobarbaz\n\e[37;41mnewline\e[39;49m", $formatter->formatAndWrap("foobarbaz\nnewline", 11)); + $this->assertSame("foobar\e[37;41mbaz\e[39;49m\n\e[37;41mnewline\e[39;49m", $formatter->formatAndWrap("foobarbaz\nnewline", 11)); + $this->assertSame("foobar\e[37;41mbazne\e[39;49m\n\e[37;41mwline\e[39;49m", $formatter->formatAndWrap("foobarbazne\nwline", 11)); + $this->assertSame("foobar\e[37;41mbazne\e[39;49m\n\e[37;41mw\e[39;49m\n\e[37;41mline\e[39;49m", $formatter->formatAndWrap("foobarbaznew\nline", 11)); $formatter = new OutputFormatter(); @@ -378,8 +384,14 @@ public function testFormatAndWrap() $this->assertSame("Â rèälly\nlöng tîtlè\nthät cöüld\nnèêd\nmúltîplê\nlínès", $formatter->formatAndWrap('Â rèälly löng tîtlè thät cöüld nèêd múltîplê línès', 10)); $this->assertSame("Â rèälly\nlöng tîtlè\nthät cöüld\nnèêd\nmúltîplê\n línès", $formatter->formatAndWrap("Â rèälly löng tîtlè thät cöüld nèêd múltîplê\n línès", 10)); $this->assertSame('', $formatter->formatAndWrap(null, 5)); - $this->assertSame("non-empty-array given.\n🪪\n argument.type", $formatter->formatAndWrap("non-empty-array given.\n🪪 argument.type", 38)); + $this->assertSame("non-empty-array given.\n🪪 argument.type", $formatter->formatAndWrap("non-empty-array given.\n🪪 argument.type", 38)); $this->assertSame("Usuário {{user_name}} não é válid\no.", $formatter->formatAndWrap('Usuário {{user_name}} não é válido.', 50)); + $this->assertSame("foob\narbaz", $formatter->formatAndWrap("foob\narbaz", 7)); + $this->assertSame("foobarbaz\nnewline", $formatter->formatAndWrap("foobarbaz\nnewline", 11)); + $this->assertSame("foobarbaz\nnewline", $formatter->formatAndWrap("foobarbaz\nnewline", 11)); + $this->assertSame("foobarbaz\nnewline", $formatter->formatAndWrap("foobarbaz\nnewline", 11)); + $this->assertSame("foobarbazne\nwline", $formatter->formatAndWrap("foobarbazne\nwline", 11)); + $this->assertSame("foobarbazne\nw\nline", $formatter->formatAndWrap("foobarbaznew\nline", 11)); } }