/** * Formats a message as a block of text. * * @param string|array $messages The message to write in the block * @param string|null $type The block type (added in [] on first line) * @param string|null $style The style to apply to the whole block * @param string $prefix The prefix for the block * @param bool $padding Whether to add vertical padding */ public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false) { $this->autoPrependBlock(); $messages = is_array($messages) ? array_values($messages) : array($messages); $lines = array(); // add type if (null !== $type) { $messages[0] = sprintf('[%s] %s', $type, $messages[0]); } // wrap and add newlines for each element foreach ($messages as $key => $message) { $message = OutputFormatter::escape($message); $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - Helper::strlen($prefix), PHP_EOL, true))); if (count($messages) > 1 && $key < count($messages) - 1) { $lines[] = ''; } } if ($padding && $this->isDecorated()) { array_unshift($lines, ''); $lines[] = ''; } foreach ($lines as &$line) { $line = sprintf('%s%s', $prefix, $line); $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line)); if ($style) { $line = sprintf('<%s>%s</>', $style, $line); } } $this->writeln($lines); $this->newLine(); }
/** * Constructor. * * @param OutputInterface $output An OutputInterface instance * @param int $max Maximum steps (0 if unknown) */ public function __construct(OutputInterface $output, $max = 0) { // Disabling output when it does not support ANSI codes as it would result in a broken display anyway. $this->output = $output->isDecorated() ? $output : new NullOutput(); $this->max = (int) $max; $this->stepWidth = $this->max > 0 ? Helper::strlen($this->max) : 4; if (!self::$formatters) { self::$formatters = self::initPlaceholderFormatters(); } if (!self::$formats) { self::$formats = self::initFormats(); } $this->setFormat($this->determineBestFormat()); }
/** * Formats a message as a block of text. * * @param string|array $messages The message to write in the block * @param string|null $type The block type (added in [] on first line) * @param string|null $style The style to apply to the whole block * @param string $prefix The prefix for the block * @param bool $padding Whether to add vertical padding */ public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false) { $this->autoPrependBlock(); $messages = is_array($messages) ? array_values($messages) : array($messages); $indentLength = 0; $lines = array(); if (null !== $type) { $typePrefix = sprintf('[%s] ', $type); $indentLength = strlen($typePrefix); $lineIndentation = str_repeat(' ', $indentLength); } // wrap and add newlines for each element foreach ($messages as $key => $message) { $message = OutputFormatter::escape($message); $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - Helper::strlen($prefix) - $indentLength, PHP_EOL, true))); // prefix each line with a number of spaces equivalent to the type length if (null !== $type) { foreach ($lines as &$line) { $line = $lineIndentation === substr($line, 0, $indentLength) ? $line : $lineIndentation . $line; } } if (count($messages) > 1 && $key < count($messages) - 1) { $lines[] = ''; } } if (null !== $type) { $lines[0] = substr_replace($lines[0], $typePrefix, 0, $indentLength); } if ($padding && $this->isDecorated()) { array_unshift($lines, ''); $lines[] = ''; } foreach ($lines as &$line) { $line = sprintf('%s%s', $prefix, $line); $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line)); if ($style) { $line = sprintf('<%s>%s</>', $style, $line); } } $this->writeln($lines); $this->newLine(); }
/** * Renders table cell with padding. * * @param array $row * @param int $column * @param string $cellFormat */ private function renderCell(array $row, $column, $cellFormat) { $cell = isset($row[$column]) ? $row[$column] : ''; $width = $this->columnWidths[$column]; if ($cell instanceof TableCell && $cell->getColspan() > 1) { // add the width of the following columns(numbers of colspan). foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) { $width += $this->getColumnSeparatorWidth() + $this->columnWidths[$nextColumn]; } } // str_pad won't work properly with multi-byte strings, we need to fix the padding if (false !== ($encoding = mb_detect_encoding($cell, null, true))) { $width += strlen($cell) - mb_strwidth($cell, $encoding); } $style = $this->getColumnStyle($column); if ($cell instanceof TableSeparator) { $this->output->write(sprintf($style->getBorderFormat(), str_repeat($style->getHorizontalBorderChar(), $width))); } else { $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell); $content = sprintf($style->getCellRowContentFormat(), $cell); $this->output->write(sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $style->getPadType()))); } }
/** * Renders table cell with padding. * * @param array $row * @param int $column * @param string $cellFormat */ private function renderCell(array $row, $column, $cellFormat) { $cell = isset($row[$column]) ? $row[$column] : ''; $width = $this->getColumnWidth($column); // str_pad won't work properly with multi-byte strings, we need to fix the padding if (function_exists('mb_strlen') && false !== ($encoding = mb_detect_encoding($cell))) { $width += strlen($cell) - mb_strlen($cell, $encoding); } $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell); $content = sprintf($this->style->getCellRowContentFormat(), $cell); $this->output->write(sprintf($cellFormat, str_pad($content, $width, $this->style->getPaddingChar(), $this->style->getPadType()))); }
/** * Sets the progress bar maximal steps. * * @param int $max The progress bar max steps */ private function setMaxSteps($max) { $this->max = max(0, (int) $max); $this->stepWidth = $this->max ? Helper::strlen($this->max) : 4; }
/** * Finds a command by name or alias. * * Contrary to get, this command tries to find the best * match if you give it an abbreviation of a name or alias. * * @param string $name A command name or a command alias * * @return Command A Command instance * * @throws CommandNotFoundException When command name is incorrect or ambiguous */ public function find($name) { $allCommands = array_keys($this->commands); $expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]) . '[^:]*'; }, $name); $commands = preg_grep('{^' . $expr . '}', $allCommands); if (empty($commands) || count(preg_grep('{^' . $expr . '$}', $commands)) < 1) { if (false !== ($pos = strrpos($name, ':'))) { // check if a namespace exists and contains commands $this->findNamespace(substr($name, 0, $pos)); } $message = sprintf('Command "%s" is not defined.', $name); if ($alternatives = $this->findAlternatives($name, $allCommands)) { if (1 == count($alternatives)) { $message .= "\n\nDid you mean this?\n "; } else { $message .= "\n\nDid you mean one of these?\n "; } $message .= implode("\n ", $alternatives); } throw new CommandNotFoundException($message, $alternatives); } // filter out aliases for commands which are already on the list if (count($commands) > 1) { $commandList = $this->commands; $commands = array_filter($commands, function ($nameOrAlias) use($commandList, $commands) { $commandName = $commandList[$nameOrAlias]->getName(); return $commandName === $nameOrAlias || !in_array($commandName, $commands); }); } $exact = in_array($name, $commands, true); if (count($commands) > 1 && !$exact) { $usableWidth = $this->terminal->getWidth() - 10; $abbrevs = array_values($commands); $maxLen = 0; foreach ($abbrevs as $abbrev) { $maxLen = max(Helper::strlen($abbrev), $maxLen); } $abbrevs = array_map(function ($cmd) use($commandList, $usableWidth, $maxLen) { $abbrev = str_pad($cmd, $maxLen, ' ') . ' ' . $commandList[$cmd]->getDescription(); return Helper::strlen($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3) . '...' : $abbrev; }, array_values($commands)); $suggestions = $this->getAbbreviationSuggestions($abbrevs); throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s", $name, $suggestions), array_values($commands)); } return $this->get($exact ? $name : reset($commands)); }