annotate vendor/symfony/console/Formatter/OutputFormatter.php @ 2:92f882872392

Trusted hosts, + remove migration modules
author Chris Cannam
date Tue, 05 Dec 2017 09:26:43 +0000
parents 4c8ae668cc8c
children 1fec387a4317
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@0 24 private $styles = array();
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@0 53 $len = strlen($text);
Chris@0 54 $text = rtrim($text, '\\');
Chris@0 55 $text .= str_repeat('<<', $len - strlen($text));
Chris@0 56 }
Chris@0 57
Chris@0 58 return $text;
Chris@0 59 }
Chris@0 60
Chris@0 61 /**
Chris@0 62 * Initializes console output formatter.
Chris@0 63 *
Chris@0 64 * @param bool $decorated Whether this formatter should actually decorate strings
Chris@0 65 * @param OutputFormatterStyleInterface[] $styles Array of "name => FormatterStyle" instances
Chris@0 66 */
Chris@0 67 public function __construct($decorated = false, array $styles = array())
Chris@0 68 {
Chris@0 69 $this->decorated = (bool) $decorated;
Chris@0 70
Chris@0 71 $this->setStyle('error', new OutputFormatterStyle('white', 'red'));
Chris@0 72 $this->setStyle('info', new OutputFormatterStyle('green'));
Chris@0 73 $this->setStyle('comment', new OutputFormatterStyle('yellow'));
Chris@0 74 $this->setStyle('question', new OutputFormatterStyle('black', 'cyan'));
Chris@0 75
Chris@0 76 foreach ($styles as $name => $style) {
Chris@0 77 $this->setStyle($name, $style);
Chris@0 78 }
Chris@0 79
Chris@0 80 $this->styleStack = new OutputFormatterStyleStack();
Chris@0 81 }
Chris@0 82
Chris@0 83 /**
Chris@0 84 * {@inheritdoc}
Chris@0 85 */
Chris@0 86 public function setDecorated($decorated)
Chris@0 87 {
Chris@0 88 $this->decorated = (bool) $decorated;
Chris@0 89 }
Chris@0 90
Chris@0 91 /**
Chris@0 92 * {@inheritdoc}
Chris@0 93 */
Chris@0 94 public function isDecorated()
Chris@0 95 {
Chris@0 96 return $this->decorated;
Chris@0 97 }
Chris@0 98
Chris@0 99 /**
Chris@0 100 * {@inheritdoc}
Chris@0 101 */
Chris@0 102 public function setStyle($name, OutputFormatterStyleInterface $style)
Chris@0 103 {
Chris@0 104 $this->styles[strtolower($name)] = $style;
Chris@0 105 }
Chris@0 106
Chris@0 107 /**
Chris@0 108 * {@inheritdoc}
Chris@0 109 */
Chris@0 110 public function hasStyle($name)
Chris@0 111 {
Chris@0 112 return isset($this->styles[strtolower($name)]);
Chris@0 113 }
Chris@0 114
Chris@0 115 /**
Chris@0 116 * {@inheritdoc}
Chris@0 117 */
Chris@0 118 public function getStyle($name)
Chris@0 119 {
Chris@0 120 if (!$this->hasStyle($name)) {
Chris@0 121 throw new InvalidArgumentException(sprintf('Undefined style: %s', $name));
Chris@0 122 }
Chris@0 123
Chris@0 124 return $this->styles[strtolower($name)];
Chris@0 125 }
Chris@0 126
Chris@0 127 /**
Chris@0 128 * {@inheritdoc}
Chris@0 129 */
Chris@0 130 public function format($message)
Chris@0 131 {
Chris@0 132 $message = (string) $message;
Chris@0 133 $offset = 0;
Chris@0 134 $output = '';
Chris@0 135 $tagRegex = '[a-z][a-z0-9,_=;-]*+';
Chris@0 136 preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, PREG_OFFSET_CAPTURE);
Chris@0 137 foreach ($matches[0] as $i => $match) {
Chris@0 138 $pos = $match[1];
Chris@0 139 $text = $match[0];
Chris@0 140
Chris@0 141 if (0 != $pos && '\\' == $message[$pos - 1]) {
Chris@0 142 continue;
Chris@0 143 }
Chris@0 144
Chris@0 145 // add the text up to the next tag
Chris@0 146 $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset));
Chris@0 147 $offset = $pos + strlen($text);
Chris@0 148
Chris@0 149 // opening tag?
Chris@0 150 if ($open = '/' != $text[1]) {
Chris@0 151 $tag = $matches[1][$i][0];
Chris@0 152 } else {
Chris@0 153 $tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : '';
Chris@0 154 }
Chris@0 155
Chris@0 156 if (!$open && !$tag) {
Chris@0 157 // </>
Chris@0 158 $this->styleStack->pop();
Chris@0 159 } elseif (false === $style = $this->createStyleFromString(strtolower($tag))) {
Chris@0 160 $output .= $this->applyCurrentStyle($text);
Chris@0 161 } elseif ($open) {
Chris@0 162 $this->styleStack->push($style);
Chris@0 163 } else {
Chris@0 164 $this->styleStack->pop($style);
Chris@0 165 }
Chris@0 166 }
Chris@0 167
Chris@0 168 $output .= $this->applyCurrentStyle(substr($message, $offset));
Chris@0 169
Chris@0 170 if (false !== strpos($output, '<<')) {
Chris@0 171 return strtr($output, array('\\<' => '<', '<<' => '\\'));
Chris@0 172 }
Chris@0 173
Chris@0 174 return str_replace('\\<', '<', $output);
Chris@0 175 }
Chris@0 176
Chris@0 177 /**
Chris@0 178 * @return OutputFormatterStyleStack
Chris@0 179 */
Chris@0 180 public function getStyleStack()
Chris@0 181 {
Chris@0 182 return $this->styleStack;
Chris@0 183 }
Chris@0 184
Chris@0 185 /**
Chris@0 186 * Tries to create new style instance from string.
Chris@0 187 *
Chris@0 188 * @param string $string
Chris@0 189 *
Chris@0 190 * @return OutputFormatterStyle|false false if string is not format string
Chris@0 191 */
Chris@0 192 private function createStyleFromString($string)
Chris@0 193 {
Chris@0 194 if (isset($this->styles[$string])) {
Chris@0 195 return $this->styles[$string];
Chris@0 196 }
Chris@0 197
Chris@0 198 if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, PREG_SET_ORDER)) {
Chris@0 199 return false;
Chris@0 200 }
Chris@0 201
Chris@0 202 $style = new OutputFormatterStyle();
Chris@0 203 foreach ($matches as $match) {
Chris@0 204 array_shift($match);
Chris@0 205
Chris@0 206 if ('fg' == $match[0]) {
Chris@0 207 $style->setForeground($match[1]);
Chris@0 208 } elseif ('bg' == $match[0]) {
Chris@0 209 $style->setBackground($match[1]);
Chris@0 210 } elseif ('options' === $match[0]) {
Chris@0 211 preg_match_all('([^,;]+)', $match[1], $options);
Chris@0 212 $options = array_shift($options);
Chris@0 213 foreach ($options as $option) {
Chris@0 214 try {
Chris@0 215 $style->setOption($option);
Chris@0 216 } catch (\InvalidArgumentException $e) {
Chris@0 217 @trigger_error(sprintf('Unknown style options are deprecated since version 3.2 and will be removed in 4.0. Exception "%s".', $e->getMessage()), E_USER_DEPRECATED);
Chris@0 218
Chris@0 219 return false;
Chris@0 220 }
Chris@0 221 }
Chris@0 222 } else {
Chris@0 223 return false;
Chris@0 224 }
Chris@0 225 }
Chris@0 226
Chris@0 227 return $style;
Chris@0 228 }
Chris@0 229
Chris@0 230 /**
Chris@0 231 * Applies current style from stack to text, if must be applied.
Chris@0 232 *
Chris@0 233 * @param string $text Input text
Chris@0 234 *
Chris@0 235 * @return string Styled text
Chris@0 236 */
Chris@0 237 private function applyCurrentStyle($text)
Chris@0 238 {
Chris@0 239 return $this->isDecorated() && strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;
Chris@0 240 }
Chris@0 241 }