annotate vendor/symfony/console/Formatter/OutputFormatter.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\Console\Formatter;
Chris@0 13
Chris@0 14 use Symfony\Component\Console\Exception\InvalidArgumentException;
Chris@0 15
Chris@0 16 /**
Chris@0 17 * Formatter class for console output.
Chris@0 18 *
Chris@0 19 * @author Konstantin Kudryashov <ever.zet@gmail.com>
Chris@0 20 */
Chris@0 21 class OutputFormatter implements OutputFormatterInterface
Chris@0 22 {
Chris@0 23 private $decorated;
Chris@17 24 private $styles = [];
Chris@0 25 private $styleStack;
Chris@0 26
Chris@0 27 /**
Chris@0 28 * Escapes "<" special char in given text.
Chris@0 29 *
Chris@0 30 * @param string $text Text to escape
Chris@0 31 *
Chris@0 32 * @return string Escaped text
Chris@0 33 */
Chris@0 34 public static function escape($text)
Chris@0 35 {
Chris@0 36 $text = preg_replace('/([^\\\\]?)</', '$1\\<', $text);
Chris@0 37
Chris@0 38 return self::escapeTrailingBackslash($text);
Chris@0 39 }
Chris@0 40
Chris@0 41 /**
Chris@0 42 * Escapes trailing "\" in given text.
Chris@0 43 *
Chris@0 44 * @param string $text Text to escape
Chris@0 45 *
Chris@0 46 * @return string Escaped text
Chris@0 47 *
Chris@0 48 * @internal
Chris@0 49 */
Chris@0 50 public static function escapeTrailingBackslash($text)
Chris@0 51 {
Chris@0 52 if ('\\' === substr($text, -1)) {
Chris@17 53 $len = \strlen($text);
Chris@0 54 $text = rtrim($text, '\\');
Chris@14 55 $text = str_replace("\0", '', $text);
Chris@17 56 $text .= str_repeat("\0", $len - \strlen($text));
Chris@0 57 }
Chris@0 58
Chris@0 59 return $text;
Chris@0 60 }
Chris@0 61
Chris@0 62 /**
Chris@0 63 * Initializes console output formatter.
Chris@0 64 *
Chris@0 65 * @param bool $decorated Whether this formatter should actually decorate strings
Chris@0 66 * @param OutputFormatterStyleInterface[] $styles Array of "name => FormatterStyle" instances
Chris@0 67 */
Chris@17 68 public function __construct($decorated = false, array $styles = [])
Chris@0 69 {
Chris@0 70 $this->decorated = (bool) $decorated;
Chris@0 71
Chris@0 72 $this->setStyle('error', new OutputFormatterStyle('white', 'red'));
Chris@0 73 $this->setStyle('info', new OutputFormatterStyle('green'));
Chris@0 74 $this->setStyle('comment', new OutputFormatterStyle('yellow'));
Chris@0 75 $this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));
Chris@0 76
Chris@0 77 foreach ($styles as $name => $style) {
Chris@0 78 $this->setStyle($name, $style);
Chris@0 79 }
Chris@0 80
Chris@0 81 $this->styleStack = new OutputFormatterStyleStack();
Chris@0 82 }
Chris@0 83
Chris@0 84 /**
Chris@0 85 * {@inheritdoc}
Chris@0 86 */
Chris@0 87 public function setDecorated($decorated)
Chris@0 88 {
Chris@0 89 $this->decorated = (bool) $decorated;
Chris@0 90 }
Chris@0 91
Chris@0 92 /**
Chris@0 93 * {@inheritdoc}
Chris@0 94 */
Chris@0 95 public function isDecorated()
Chris@0 96 {
Chris@0 97 return $this->decorated;
Chris@0 98 }
Chris@0 99
Chris@0 100 /**
Chris@0 101 * {@inheritdoc}
Chris@0 102 */
Chris@0 103 public function setStyle($name, OutputFormatterStyleInterface $style)
Chris@0 104 {
Chris@0 105 $this->styles[strtolower($name)] = $style;
Chris@0 106 }
Chris@0 107
Chris@0 108 /**
Chris@0 109 * {@inheritdoc}
Chris@0 110 */
Chris@0 111 public function hasStyle($name)
Chris@0 112 {
Chris@0 113 return isset($this->styles[strtolower($name)]);
Chris@0 114 }
Chris@0 115
Chris@0 116 /**
Chris@0 117 * {@inheritdoc}
Chris@0 118 */
Chris@0 119 public function getStyle($name)
Chris@0 120 {
Chris@0 121 if (!$this->hasStyle($name)) {
Chris@0 122 throw new InvalidArgumentException(sprintf('Undefined style: %s', $name));
Chris@0 123 }
Chris@0 124
Chris@0 125 return $this->styles[strtolower($name)];
Chris@0 126 }
Chris@0 127
Chris@0 128 /**
Chris@0 129 * {@inheritdoc}
Chris@0 130 */
Chris@0 131 public function format($message)
Chris@0 132 {
Chris@0 133 $message = (string) $message;
Chris@0 134 $offset = 0;
Chris@0 135 $output = '';
Chris@0 136 $tagRegex = '[a-z][a-z0-9,_=;-]*+';
Chris@0 137 preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, PREG_OFFSET_CAPTURE);
Chris@0 138 foreach ($matches[0] as $i => $match) {
Chris@0 139 $pos = $match[1];
Chris@0 140 $text = $match[0];
Chris@0 141
Chris@0 142 if (0 != $pos && '\\' == $message[$pos - 1]) {
Chris@0 143 continue;
Chris@0 144 }
Chris@0 145
Chris@0 146 // add the text up to the next tag
Chris@0 147 $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset));
Chris@17 148 $offset = $pos + \strlen($text);
Chris@0 149
Chris@0 150 // opening tag?
Chris@0 151 if ($open = '/' != $text[1]) {
Chris@0 152 $tag = $matches[1][$i][0];
Chris@0 153 } else {
Chris@0 154 $tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : '';
Chris@0 155 }
Chris@0 156
Chris@0 157 if (!$open && !$tag) {
Chris@0 158 // </>
Chris@0 159 $this->styleStack->pop();
Chris@17 160 } elseif (false === $style = $this->createStyleFromString($tag)) {
Chris@0 161 $output .= $this->applyCurrentStyle($text);
Chris@0 162 } elseif ($open) {
Chris@0 163 $this->styleStack->push($style);
Chris@0 164 } else {
Chris@0 165 $this->styleStack->pop($style);
Chris@0 166 }
Chris@0 167 }
Chris@0 168
Chris@0 169 $output .= $this->applyCurrentStyle(substr($message, $offset));
Chris@0 170
Chris@14 171 if (false !== strpos($output, "\0")) {
Chris@17 172 return strtr($output, ["\0" => '\\', '\\<' => '<']);
Chris@0 173 }
Chris@0 174
Chris@0 175 return str_replace('\\<', '<', $output);
Chris@0 176 }
Chris@0 177
Chris@0 178 /**
Chris@0 179 * @return OutputFormatterStyleStack
Chris@0 180 */
Chris@0 181 public function getStyleStack()
Chris@0 182 {
Chris@0 183 return $this->styleStack;
Chris@0 184 }
Chris@0 185
Chris@0 186 /**
Chris@0 187 * Tries to create new style instance from string.
Chris@0 188 *
Chris@0 189 * @param string $string
Chris@0 190 *
Chris@0 191 * @return OutputFormatterStyle|false false if string is not format string
Chris@0 192 */
Chris@0 193 private function createStyleFromString($string)
Chris@0 194 {
Chris@0 195 if (isset($this->styles[$string])) {
Chris@0 196 return $this->styles[$string];
Chris@0 197 }
Chris@0 198
Chris@0 199 if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, PREG_SET_ORDER)) {
Chris@0 200 return false;
Chris@0 201 }
Chris@0 202
Chris@0 203 $style = new OutputFormatterStyle();
Chris@0 204 foreach ($matches as $match) {
Chris@0 205 array_shift($match);
Chris@17 206 $match[0] = strtolower($match[0]);
Chris@0 207
Chris@0 208 if ('fg' == $match[0]) {
Chris@17 209 $style->setForeground(strtolower($match[1]));
Chris@0 210 } elseif ('bg' == $match[0]) {
Chris@17 211 $style->setBackground(strtolower($match[1]));
Chris@0 212 } elseif ('options' === $match[0]) {
Chris@17 213 preg_match_all('([^,;]+)', strtolower($match[1]), $options);
Chris@0 214 $options = array_shift($options);
Chris@0 215 foreach ($options as $option) {
Chris@0 216 try {
Chris@0 217 $style->setOption($option);
Chris@0 218 } catch (\InvalidArgumentException $e) {
Chris@14 219 @trigger_error(sprintf('Unknown style options are deprecated since Symfony 3.2 and will be removed in 4.0. Exception "%s".', $e->getMessage()), E_USER_DEPRECATED);
Chris@0 220
Chris@0 221 return false;
Chris@0 222 }
Chris@0 223 }
Chris@0 224 } else {
Chris@0 225 return false;
Chris@0 226 }
Chris@0 227 }
Chris@0 228
Chris@0 229 return $style;
Chris@0 230 }
Chris@0 231
Chris@0 232 /**
Chris@0 233 * Applies current style from stack to text, if must be applied.
Chris@0 234 *
Chris@0 235 * @param string $text Input text
Chris@0 236 *
Chris@0 237 * @return string Styled text
Chris@0 238 */
Chris@0 239 private function applyCurrentStyle($text)
Chris@0 240 {
Chris@17 241 return $this->isDecorated() && \strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;
Chris@0 242 }
Chris@0 243 }