annotate vendor/jakub-onderka/php-console-highlighter/src/Highlighter.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@17 1 <?php
Chris@17 2 namespace JakubOnderka\PhpConsoleHighlighter;
Chris@17 3
Chris@17 4 use JakubOnderka\PhpConsoleColor\ConsoleColor;
Chris@17 5
Chris@17 6 class Highlighter
Chris@17 7 {
Chris@17 8 const TOKEN_DEFAULT = 'token_default',
Chris@17 9 TOKEN_COMMENT = 'token_comment',
Chris@17 10 TOKEN_STRING = 'token_string',
Chris@17 11 TOKEN_HTML = 'token_html',
Chris@17 12 TOKEN_KEYWORD = 'token_keyword';
Chris@17 13
Chris@17 14 const ACTUAL_LINE_MARK = 'actual_line_mark',
Chris@17 15 LINE_NUMBER = 'line_number';
Chris@17 16
Chris@17 17 /** @var ConsoleColor */
Chris@17 18 private $color;
Chris@17 19
Chris@17 20 /** @var array */
Chris@17 21 private $defaultTheme = array(
Chris@17 22 self::TOKEN_STRING => 'red',
Chris@17 23 self::TOKEN_COMMENT => 'yellow',
Chris@17 24 self::TOKEN_KEYWORD => 'green',
Chris@17 25 self::TOKEN_DEFAULT => 'default',
Chris@17 26 self::TOKEN_HTML => 'cyan',
Chris@17 27
Chris@17 28 self::ACTUAL_LINE_MARK => 'red',
Chris@17 29 self::LINE_NUMBER => 'dark_gray',
Chris@17 30 );
Chris@17 31
Chris@17 32 /**
Chris@17 33 * @param ConsoleColor $color
Chris@17 34 * @throws \JakubOnderka\PhpConsoleColor\InvalidStyleException
Chris@17 35 */
Chris@17 36 public function __construct(ConsoleColor $color)
Chris@17 37 {
Chris@17 38 $this->color = $color;
Chris@17 39
Chris@17 40 foreach ($this->defaultTheme as $name => $styles) {
Chris@17 41 if (!$this->color->hasTheme($name)) {
Chris@17 42 $this->color->addTheme($name, $styles);
Chris@17 43 }
Chris@17 44 }
Chris@17 45 }
Chris@17 46
Chris@17 47 /**
Chris@17 48 * @param string $source
Chris@17 49 * @param int $lineNumber
Chris@17 50 * @param int $linesBefore
Chris@17 51 * @param int $linesAfter
Chris@17 52 * @return string
Chris@17 53 * @throws \JakubOnderka\PhpConsoleColor\InvalidStyleException
Chris@17 54 * @throws \InvalidArgumentException
Chris@17 55 */
Chris@17 56 public function getCodeSnippet($source, $lineNumber, $linesBefore = 2, $linesAfter = 2)
Chris@17 57 {
Chris@17 58 $tokenLines = $this->getHighlightedLines($source);
Chris@17 59
Chris@17 60 $offset = $lineNumber - $linesBefore - 1;
Chris@17 61 $offset = max($offset, 0);
Chris@17 62 $length = $linesAfter + $linesBefore + 1;
Chris@17 63 $tokenLines = array_slice($tokenLines, $offset, $length, $preserveKeys = true);
Chris@17 64
Chris@17 65 $lines = $this->colorLines($tokenLines);
Chris@17 66
Chris@17 67 return $this->lineNumbers($lines, $lineNumber);
Chris@17 68 }
Chris@17 69
Chris@17 70 /**
Chris@17 71 * @param string $source
Chris@17 72 * @return string
Chris@17 73 * @throws \JakubOnderka\PhpConsoleColor\InvalidStyleException
Chris@17 74 * @throws \InvalidArgumentException
Chris@17 75 */
Chris@17 76 public function getWholeFile($source)
Chris@17 77 {
Chris@17 78 $tokenLines = $this->getHighlightedLines($source);
Chris@17 79 $lines = $this->colorLines($tokenLines);
Chris@17 80 return implode(PHP_EOL, $lines);
Chris@17 81 }
Chris@17 82
Chris@17 83 /**
Chris@17 84 * @param string $source
Chris@17 85 * @return string
Chris@17 86 * @throws \JakubOnderka\PhpConsoleColor\InvalidStyleException
Chris@17 87 * @throws \InvalidArgumentException
Chris@17 88 */
Chris@17 89 public function getWholeFileWithLineNumbers($source)
Chris@17 90 {
Chris@17 91 $tokenLines = $this->getHighlightedLines($source);
Chris@17 92 $lines = $this->colorLines($tokenLines);
Chris@17 93 return $this->lineNumbers($lines);
Chris@17 94 }
Chris@17 95
Chris@17 96 /**
Chris@17 97 * @param string $source
Chris@17 98 * @return array
Chris@17 99 */
Chris@17 100 private function getHighlightedLines($source)
Chris@17 101 {
Chris@17 102 $source = str_replace(array("\r\n", "\r"), "\n", $source);
Chris@17 103 $tokens = $this->tokenize($source);
Chris@17 104 return $this->splitToLines($tokens);
Chris@17 105 }
Chris@17 106
Chris@17 107 /**
Chris@17 108 * @param string $source
Chris@17 109 * @return array
Chris@17 110 */
Chris@17 111 private function tokenize($source)
Chris@17 112 {
Chris@17 113 $tokens = token_get_all($source);
Chris@17 114
Chris@17 115 $output = array();
Chris@17 116 $currentType = null;
Chris@17 117 $buffer = '';
Chris@17 118
Chris@17 119 foreach ($tokens as $token) {
Chris@17 120 if (is_array($token)) {
Chris@17 121 switch ($token[0]) {
Chris@17 122 case T_WHITESPACE:
Chris@17 123 break;
Chris@17 124
Chris@17 125 case T_OPEN_TAG:
Chris@17 126 case T_OPEN_TAG_WITH_ECHO:
Chris@17 127 case T_CLOSE_TAG:
Chris@17 128 case T_STRING:
Chris@17 129 case T_VARIABLE:
Chris@17 130
Chris@17 131 // Constants
Chris@17 132 case T_DIR:
Chris@17 133 case T_FILE:
Chris@17 134 case T_METHOD_C:
Chris@17 135 case T_DNUMBER:
Chris@17 136 case T_LNUMBER:
Chris@17 137 case T_NS_C:
Chris@17 138 case T_LINE:
Chris@17 139 case T_CLASS_C:
Chris@17 140 case T_FUNC_C:
Chris@17 141 case T_TRAIT_C:
Chris@17 142 $newType = self::TOKEN_DEFAULT;
Chris@17 143 break;
Chris@17 144
Chris@17 145 case T_COMMENT:
Chris@17 146 case T_DOC_COMMENT:
Chris@17 147 $newType = self::TOKEN_COMMENT;
Chris@17 148 break;
Chris@17 149
Chris@17 150 case T_ENCAPSED_AND_WHITESPACE:
Chris@17 151 case T_CONSTANT_ENCAPSED_STRING:
Chris@17 152 $newType = self::TOKEN_STRING;
Chris@17 153 break;
Chris@17 154
Chris@17 155 case T_INLINE_HTML:
Chris@17 156 $newType = self::TOKEN_HTML;
Chris@17 157 break;
Chris@17 158
Chris@17 159 default:
Chris@17 160 $newType = self::TOKEN_KEYWORD;
Chris@17 161 }
Chris@17 162 } else {
Chris@17 163 $newType = $token === '"' ? self::TOKEN_STRING : self::TOKEN_KEYWORD;
Chris@17 164 }
Chris@17 165
Chris@17 166 if ($currentType === null) {
Chris@17 167 $currentType = $newType;
Chris@17 168 }
Chris@17 169
Chris@17 170 if ($currentType !== $newType) {
Chris@17 171 $output[] = array($currentType, $buffer);
Chris@17 172 $buffer = '';
Chris@17 173 $currentType = $newType;
Chris@17 174 }
Chris@17 175
Chris@17 176 $buffer .= is_array($token) ? $token[1] : $token;
Chris@17 177 }
Chris@17 178
Chris@17 179 if (isset($newType)) {
Chris@17 180 $output[] = array($newType, $buffer);
Chris@17 181 }
Chris@17 182
Chris@17 183 return $output;
Chris@17 184 }
Chris@17 185
Chris@17 186 /**
Chris@17 187 * @param array $tokens
Chris@17 188 * @return array
Chris@17 189 */
Chris@17 190 private function splitToLines(array $tokens)
Chris@17 191 {
Chris@17 192 $lines = array();
Chris@17 193
Chris@17 194 $line = array();
Chris@17 195 foreach ($tokens as $token) {
Chris@17 196 foreach (explode("\n", $token[1]) as $count => $tokenLine) {
Chris@17 197 if ($count > 0) {
Chris@17 198 $lines[] = $line;
Chris@17 199 $line = array();
Chris@17 200 }
Chris@17 201
Chris@17 202 if ($tokenLine === '') {
Chris@17 203 continue;
Chris@17 204 }
Chris@17 205
Chris@17 206 $line[] = array($token[0], $tokenLine);
Chris@17 207 }
Chris@17 208 }
Chris@17 209
Chris@17 210 $lines[] = $line;
Chris@17 211
Chris@17 212 return $lines;
Chris@17 213 }
Chris@17 214
Chris@17 215 /**
Chris@17 216 * @param array $tokenLines
Chris@17 217 * @return array
Chris@17 218 * @throws \JakubOnderka\PhpConsoleColor\InvalidStyleException
Chris@17 219 * @throws \InvalidArgumentException
Chris@17 220 */
Chris@17 221 private function colorLines(array $tokenLines)
Chris@17 222 {
Chris@17 223 $lines = array();
Chris@17 224 foreach ($tokenLines as $lineCount => $tokenLine) {
Chris@17 225 $line = '';
Chris@17 226 foreach ($tokenLine as $token) {
Chris@17 227 list($tokenType, $tokenValue) = $token;
Chris@17 228 if ($this->color->hasTheme($tokenType)) {
Chris@17 229 $line .= $this->color->apply($tokenType, $tokenValue);
Chris@17 230 } else {
Chris@17 231 $line .= $tokenValue;
Chris@17 232 }
Chris@17 233 }
Chris@17 234 $lines[$lineCount] = $line;
Chris@17 235 }
Chris@17 236
Chris@17 237 return $lines;
Chris@17 238 }
Chris@17 239
Chris@17 240 /**
Chris@17 241 * @param array $lines
Chris@17 242 * @param null|int $markLine
Chris@17 243 * @return string
Chris@17 244 * @throws \JakubOnderka\PhpConsoleColor\InvalidStyleException
Chris@17 245 */
Chris@17 246 private function lineNumbers(array $lines, $markLine = null)
Chris@17 247 {
Chris@17 248 end($lines);
Chris@17 249 $lineStrlen = strlen(key($lines) + 1);
Chris@17 250
Chris@17 251 $snippet = '';
Chris@17 252 foreach ($lines as $i => $line) {
Chris@17 253 if ($markLine !== null) {
Chris@17 254 $snippet .= ($markLine === $i + 1 ? $this->color->apply(self::ACTUAL_LINE_MARK, ' > ') : ' ');
Chris@17 255 }
Chris@17 256
Chris@17 257 $snippet .= $this->color->apply(self::LINE_NUMBER, str_pad($i + 1, $lineStrlen, ' ', STR_PAD_LEFT) . '| ');
Chris@17 258 $snippet .= $line . PHP_EOL;
Chris@17 259 }
Chris@17 260
Chris@17 261 return $snippet;
Chris@17 262 }
Chris@17 263 }