Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 169 |
Row | |
0.00% |
0 / 1 |
|
0.00% |
0 / 11 |
5402 | |
0.00% |
0 / 169 |
new | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 5 |
|||
__construct | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
__get | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
__set | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
__toString | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
__debugInfo | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
insertChar | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
appendString | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
deleteChar | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 5 |
|||
update | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
updateSyntax | |
0.00% |
0 / 1 |
1332 | |
0.00% |
0 / 81 |
|||
updateSyntaxPHP | |
0.00% |
0 / 1 |
506 | |
0.00% |
0 / 61 |
1 | <?php declare(strict_types=1); |
2 | |
3 | namespace Aviat\Kilo; |
4 | |
5 | use Aviat\Kilo\Enum\Highlight; |
6 | use Aviat\Kilo\Enum\KeyCode; |
7 | |
8 | /** |
9 | * @property-read int size |
10 | * @property-read int rsize |
11 | */ |
12 | class Row { |
13 | use Traits\MagicProperties; |
14 | |
15 | private string $chars = ''; |
16 | public string $render = ''; |
17 | |
18 | public array $hl = []; |
19 | |
20 | public int $idx; |
21 | |
22 | // This feels dirty... |
23 | private Editor $parent; |
24 | private bool $hlOpenComment = FALSE; |
25 | |
26 | private const T_RAW = -1; |
27 | |
28 | private array $phpTokenHighlightMap = [ |
29 | // Delimiters |
30 | T_ARRAY => Highlight::DELIMITER, |
31 | T_CURLY_OPEN => Highlight::DELIMITER, |
32 | T_DOLLAR_OPEN_CURLY_BRACES => Highlight::DELIMITER, |
33 | T_OPEN_TAG => Highlight::DELIMITER, |
34 | T_OPEN_TAG_WITH_ECHO => Highlight::DELIMITER, |
35 | T_CLOSE_TAG => Highlight::DELIMITER, |
36 | T_START_HEREDOC => Highlight::DELIMITER, |
37 | T_END_HEREDOC => Highlight::DELIMITER, |
38 | |
39 | // Number literals and magic constants |
40 | T_DIR => Highlight::NUMBER, |
41 | T_TRAIT_C => Highlight::NUMBER, |
42 | T_DNUMBER => Highlight::NUMBER, |
43 | T_LNUMBER => Highlight::NUMBER, |
44 | |
45 | // String literals |
46 | T_CONSTANT_ENCAPSED_STRING => Highlight::STRING, |
47 | T_ENCAPSED_AND_WHITESPACE => Highlight::STRING, |
48 | |
49 | // Simple variables |
50 | T_VARIABLE => Highlight::VARIABLE, |
51 | T_STRING_VARNAME => Highlight::VARIABLE, |
52 | |
53 | // Operators |
54 | T_AS => Highlight::OPERATOR, |
55 | T_AND_EQUAL => Highlight::OPERATOR, |
56 | T_BOOLEAN_AND => Highlight::OPERATOR, |
57 | T_BOOLEAN_OR => Highlight::OPERATOR, |
58 | T_COALESCE => Highlight::OPERATOR, |
59 | T_CONCAT_EQUAL => Highlight::OPERATOR, |
60 | T_DEC => Highlight::OPERATOR, |
61 | T_DIV_EQUAL => Highlight::OPERATOR, |
62 | T_DOUBLE_ARROW => Highlight::OPERATOR, |
63 | T_DOUBLE_COLON => Highlight::OPERATOR, |
64 | T_ELLIPSIS => Highlight::OPERATOR, |
65 | T_INC => Highlight::OPERATOR, |
66 | T_IS_EQUAL => Highlight::OPERATOR, |
67 | T_IS_GREATER_OR_EQUAL => Highlight::OPERATOR, |
68 | T_IS_IDENTICAL => Highlight::OPERATOR, |
69 | T_IS_NOT_EQUAL => Highlight::OPERATOR, |
70 | T_IS_NOT_IDENTICAL => Highlight::OPERATOR, |
71 | T_IS_SMALLER_OR_EQUAL => Highlight::OPERATOR, |
72 | T_SPACESHIP => Highlight::OPERATOR, |
73 | T_LOGICAL_AND => Highlight::OPERATOR, |
74 | T_LOGICAL_OR => Highlight::OPERATOR, |
75 | T_LOGICAL_XOR => Highlight::OPERATOR, |
76 | T_MINUS_EQUAL => Highlight::OPERATOR, |
77 | T_MOD_EQUAL => Highlight::OPERATOR, |
78 | T_MUL_EQUAL => Highlight::OPERATOR, |
79 | T_NS_SEPARATOR => Highlight::OPERATOR, |
80 | T_NULLSAFE_OBJECT_OPERATOR => Highlight::OPERATOR, |
81 | T_OBJECT_OPERATOR => Highlight::OPERATOR, |
82 | T_OR_EQUAL => Highlight::OPERATOR, |
83 | T_PLUS_EQUAL => Highlight::OPERATOR, |
84 | T_POW => Highlight::OPERATOR, |
85 | T_POW_EQUAL => Highlight::OPERATOR, |
86 | T_SL => Highlight::OPERATOR, |
87 | T_SL_EQUAL => Highlight::OPERATOR, |
88 | T_SR => Highlight::OPERATOR, |
89 | T_SR_EQUAL => Highlight::OPERATOR, |
90 | T_XOR_EQUAL => Highlight::OPERATOR, |
91 | |
92 | // Keywords1 |
93 | T_ABSTRACT => Highlight::KEYWORD1, |
94 | T_AS => Highlight::KEYWORD1, |
95 | T_BREAK => Highlight::KEYWORD1, |
96 | T_CASE => Highlight::KEYWORD1, |
97 | T_CATCH => Highlight::KEYWORD1, |
98 | T_CLASS => Highlight::KEYWORD1, |
99 | T_CLONE => Highlight::KEYWORD1, |
100 | T_CONST => Highlight::KEYWORD1, |
101 | T_CONTINUE => Highlight::KEYWORD1, |
102 | T_DECLARE => Highlight::KEYWORD1, |
103 | T_DEFAULT => Highlight::KEYWORD1, |
104 | T_DO => Highlight::KEYWORD1, |
105 | T_ELSE => Highlight::KEYWORD1, |
106 | T_ELSEIF => Highlight::KEYWORD1, |
107 | T_ENDDECLARE => Highlight::KEYWORD1, |
108 | T_ENDFOR => Highlight::KEYWORD1, |
109 | T_ENDFOREACH => Highlight::KEYWORD1, |
110 | T_ENDIF => Highlight::KEYWORD1, |
111 | T_ENDSWITCH => Highlight::KEYWORD1, |
112 | T_ENDWHILE => Highlight::KEYWORD1, |
113 | T_EXIT => Highlight::KEYWORD1, |
114 | T_EXTENDS => Highlight::KEYWORD1, |
115 | T_FINAL => Highlight::KEYWORD1, |
116 | T_FINALLY => Highlight::KEYWORD1, |
117 | T_FN => Highlight::KEYWORD1, |
118 | T_FOR => Highlight::KEYWORD1, |
119 | T_FOREACH => Highlight::KEYWORD1, |
120 | T_FUNCTION => Highlight::KEYWORD1, |
121 | T_GLOBAL => Highlight::KEYWORD1, |
122 | T_GOTO => Highlight::KEYWORD1, |
123 | T_HALT_COMPILER => Highlight::KEYWORD1, |
124 | T_IF => Highlight::KEYWORD1, |
125 | T_IMPLEMENTS => Highlight::KEYWORD1, |
126 | T_INSTANCEOF => Highlight::KEYWORD1, |
127 | T_INSTEADOF => Highlight::KEYWORD1, |
128 | T_INTERFACE => Highlight::KEYWORD1, |
129 | T_NAMESPACE => Highlight::KEYWORD1, |
130 | T_MATCH => Highlight::KEYWORD1, |
131 | T_NEW => Highlight::KEYWORD1, |
132 | T_PRIVATE => Highlight::KEYWORD1, |
133 | T_PUBLIC => Highlight::KEYWORD1, |
134 | T_PROTECTED => Highlight::KEYWORD1, |
135 | T_RETURN => Highlight::KEYWORD1, |
136 | T_STATIC => Highlight::KEYWORD1, |
137 | T_SWITCH => Highlight::KEYWORD1, |
138 | T_THROW => Highlight::KEYWORD1, |
139 | T_TRAIT => Highlight::KEYWORD1, |
140 | T_TRY => Highlight::KEYWORD1, |
141 | T_USE => Highlight::KEYWORD1, |
142 | T_VAR => Highlight::KEYWORD1, |
143 | T_WHILE => Highlight::KEYWORD1, |
144 | T_YIELD => Highlight::KEYWORD1, |
145 | T_YIELD_FROM => Highlight::KEYWORD1, |
146 | |
147 | // Not string literals, but identifiers, keywords, etc. |
148 | // T_STRING => Highlight::KEYWORD2, |
149 | |
150 | // Types and casts |
151 | T_ARRAY_CAST => Highlight::KEYWORD2, |
152 | T_BOOL_CAST => Highlight::KEYWORD2, |
153 | T_CALLABLE => Highlight::KEYWORD2, |
154 | T_DOUBLE_CAST => Highlight::KEYWORD2, |
155 | T_INT_CAST => Highlight::KEYWORD2, |
156 | T_OBJECT_CAST => Highlight::KEYWORD2, |
157 | T_STRING_CAST => Highlight::KEYWORD2, |
158 | T_UNSET_CAST => Highlight::KEYWORD2, |
159 | |
160 | // Invalid syntax |
161 | T_BAD_CHARACTER => Highlight::INVALID, |
162 | ]; |
163 | |
164 | private array $phpCharacterHighlightMap = [ |
165 | // Delimiter characters |
166 | '[' => Highlight::DELIMITER, |
167 | ']' => Highlight::DELIMITER, |
168 | '{' => Highlight::DELIMITER, |
169 | '}' => Highlight::DELIMITER, |
170 | '(' => Highlight::DELIMITER, |
171 | ')' => Highlight::DELIMITER, |
172 | '"' => Highlight::DELIMITER, |
173 | "'" => Highlight::DELIMITER, |
174 | |
175 | // Single character operators |
176 | '?' => Highlight::OPERATOR, |
177 | ',' => Highlight::OPERATOR, |
178 | ';' => Highlight::OPERATOR, |
179 | ':' => Highlight::OPERATOR, |
180 | '^' => Highlight::OPERATOR, |
181 | '%' => Highlight::OPERATOR, |
182 | '+' => Highlight::OPERATOR, |
183 | '-' => Highlight::OPERATOR, |
184 | '*' => Highlight::OPERATOR, |
185 | '/' => Highlight::OPERATOR, |
186 | '.' => Highlight::OPERATOR, |
187 | '|' => Highlight::OPERATOR, |
188 | '~' => Highlight::OPERATOR, |
189 | '>' => Highlight::OPERATOR, |
190 | '<' => Highlight::OPERATOR, |
191 | '=' => Highlight::OPERATOR, |
192 | '!' => Highlight::OPERATOR, |
193 | ]; |
194 | |
195 | public static function new(Editor $parent, string $chars, int $idx): self |
196 | { |
197 | $self = new self(); |
198 | $self->chars = $chars; |
199 | $self->parent = $parent; |
200 | $self->idx = $idx; |
201 | |
202 | return $self; |
203 | } |
204 | |
205 | private function __construct() {} |
206 | |
207 | public function __get(string $name) |
208 | { |
209 | return match ($name) |
210 | { |
211 | 'size' => strlen($this->chars), |
212 | 'rsize' => strlen($this->render), |
213 | 'chars' => $this->chars, |
214 | default => NULL, |
215 | }; |
216 | } |
217 | |
218 | public function __set(string $key, mixed $value): void |
219 | { |
220 | if ($key === 'chars') |
221 | { |
222 | $this->chars = $value; |
223 | $this->update(); |
224 | } |
225 | } |
226 | |
227 | public function __toString(): string |
228 | { |
229 | return $this->chars . "\n"; |
230 | } |
231 | |
232 | public function __debugInfo(): array |
233 | { |
234 | return [ |
235 | 'size' => $this->size, |
236 | 'rsize' => $this->rsize, |
237 | 'chars' => $this->chars, |
238 | 'render' => $this->render, |
239 | 'hl' => $this->hl, |
240 | 'hlOpenComment' => $this->hlOpenComment, |
241 | ]; |
242 | } |
243 | |
244 | public function insertChar(int $at, string $c): void |
245 | { |
246 | if ($at < 0 || $at > $this->size) |
247 | { |
248 | $this->appendString($c); |
249 | return; |
250 | } |
251 | |
252 | // Safely insert into arbitrary position in the existing string |
253 | $this->chars = substr($this->chars, 0, $at) . $c . substr($this->chars, $at); |
254 | $this->update(); |
255 | |
256 | $this->parent->dirty++; |
257 | } |
258 | |
259 | public function appendString(string $s): void |
260 | { |
261 | $this->chars .= $s; |
262 | $this->update(); |
263 | |
264 | $this->parent->dirty++; |
265 | } |
266 | |
267 | public function deleteChar(int $at): void |
268 | { |
269 | if ($at < 0 || $at >= $this->size) |
270 | { |
271 | return; |
272 | } |
273 | |
274 | $this->chars = substr_replace($this->chars, '', $at, 1); |
275 | $this->update(); |
276 | |
277 | $this->parent->dirty++; |
278 | } |
279 | |
280 | public function update(): void |
281 | { |
282 | $this->render = tabs_to_spaces($this->chars); |
283 | |
284 | $this->updateSyntax(); |
285 | } |
286 | |
287 | // ------------------------------------------------------------------------ |
288 | // ! Syntax Highlighting |
289 | // ------------------------------------------------------------------------ |
290 | |
291 | public function updateSyntax(): void |
292 | { |
293 | $this->hl = array_fill(0, $this->rsize, Highlight::NORMAL); |
294 | |
295 | if ($this->parent->syntax === NULL) |
296 | { |
297 | return; |
298 | } |
299 | |
300 | if ($this->parent->syntax->filetype === 'PHP') |
301 | { |
302 | $this->updateSyntaxPHP(); |
303 | return; |
304 | } |
305 | |
306 | $keywords1 = $this->parent->syntax->keywords1; |
307 | $keywords2 = $this->parent->syntax->keywords2; |
308 | |
309 | $scs = $this->parent->syntax->singleLineCommentStart; |
310 | $mcs = $this->parent->syntax->multiLineCommentStart; |
311 | $mce = $this->parent->syntax->multiLineCommentEnd; |
312 | |
313 | $scsLen = strlen($scs); |
314 | $mcsLen = strlen($mcs); |
315 | $mceLen = strlen($mce); |
316 | |
317 | $prevSep = TRUE; |
318 | $inString = ''; |
319 | $inComment = ($this->idx > 0 && $this->parent->rows[$this->idx - 1]->hlOpenComment); |
320 | |
321 | $i = 0; |
322 | |
323 | while ($i < $this->rsize) |
324 | { |
325 | $char = $this->render[$i]; |
326 | $prevHl = ($i > 0) ? $this->hl[$i - 1] : Highlight::NORMAL; |
327 | |
328 | // Single-line comments |
329 | if ($scsLen > 0 && $inString === '' && $inComment === FALSE |
330 | && substr($this->render, $i, $scsLen) === $scs) |
331 | { |
332 | array_replace_range($this->hl, $i, $this->rsize - $i, Highlight::COMMENT); |
333 | break; |
334 | } |
335 | |
336 | // Multi-line comments |
337 | if ($mcsLen > 0 && $mceLen > 0 && $inString === '') |
338 | { |
339 | if ($inComment) |
340 | { |
341 | $this->hl[$i] = Highlight::ML_COMMENT; |
342 | if (substr($this->render, $i, $mceLen) === $mce) |
343 | { |
344 | array_replace_range($this->hl, $i, $mceLen, Highlight::ML_COMMENT); |
345 | $i += $mceLen; |
346 | $inComment = FALSE; |
347 | $prevSep = TRUE; |
348 | continue; |
349 | } |
350 | |
351 | $i++; |
352 | continue; |
353 | } |
354 | |
355 | if (substr($this->render, $i, $mcsLen) === $mcs) |
356 | { |
357 | array_replace_range($this->hl, $i, $mcsLen, Highlight::ML_COMMENT); |
358 | $i += $mcsLen; |
359 | $inComment = TRUE; |
360 | continue; |
361 | } |
362 | } |
363 | |
364 | // String/Char literals |
365 | if ($this->parent->syntax->flags & Syntax::HIGHLIGHT_STRINGS) |
366 | { |
367 | if ($inString !== '') |
368 | { |
369 | $this->hl[$i] = Highlight::STRING; |
370 | |
371 | // Check for escaped character |
372 | if ($char === '\\' && $i+1 < $this->rsize) |
373 | { |
374 | $this->hl[$i + 1] = Highlight::STRING; |
375 | $i += 2; |
376 | continue; |
377 | } |
378 | |
379 | if ($char === $inString) |
380 | { |
381 | $inString = ''; |
382 | } |
383 | $i++; |
384 | $prevSep = 1; |
385 | continue; |
386 | } |
387 | |
388 | if ( $char === '"' || $char === '\'') |
389 | { |
390 | $inString = $char; |
391 | $this->hl[$i] = Highlight::STRING; |
392 | $i++; |
393 | continue; |
394 | } |
395 | } |
396 | |
397 | // Numbers, including decimal points |
398 | if ($this->parent->syntax->flags & Syntax::HIGHLIGHT_NUMBERS) |
399 | { |
400 | if ( |
401 | ($char === '.' && $prevHl === Highlight::NUMBER) || |
402 | (($prevSep || $prevHl === Highlight::NUMBER) && is_digit($char)) |
403 | ) |
404 | { |
405 | $this->hl[$i] = Highlight::NUMBER; |
406 | $i++; |
407 | $prevSep = FALSE; |
408 | continue; |
409 | } |
410 | } |
411 | |
412 | // Keywords |
413 | if ($prevSep) |
414 | { |
415 | $findKeywords = function (array $keywords, int $syntaxType) use (&$i): void |
416 | { |
417 | foreach ($keywords as $k) |
418 | { |
419 | $klen = strlen($k); |
420 | $nextCharOffset = $i + $klen; |
421 | $isEndOfLine = $nextCharOffset >= $this->rsize; |
422 | $nextChar = ($isEndOfLine) ? KeyCode::NULL : $this->render[$nextCharOffset]; |
423 | |
424 | if (substr($this->render, $i, $klen) === $k && is_separator($nextChar)) |
425 | { |
426 | array_replace_range($this->hl, $i, $klen, $syntaxType); |
427 | $i += $klen - 1; |
428 | break; |
429 | } |
430 | } |
431 | }; |
432 | |
433 | $findKeywords($keywords1, Highlight::KEYWORD1); |
434 | $findKeywords($keywords2, Highlight::KEYWORD2); |
435 | } |
436 | |
437 | $prevSep = is_separator($char); |
438 | $i++; |
439 | } |
440 | |
441 | $changed = $this->hlOpenComment !== $inComment; |
442 | $this->hlOpenComment = $inComment; |
443 | if ($changed && $this->idx + 1 < $this->parent->numRows) |
444 | { |
445 | // @codeCoverageIgnoreStart |
446 | $this->parent->rows[$this->idx + 1]->updateSyntax(); |
447 | // @codeCoverageIgnoreEnd |
448 | } |
449 | } |
450 | |
451 | protected function updateSyntaxPHP():void |
452 | { |
453 | $rowNum = $this->idx + 1; |
454 | |
455 | $hasRowTokens = array_key_exists($rowNum, $this->parent->tokens); |
456 | |
457 | if ( ! ( |
458 | $hasRowTokens && |
459 | $this->idx < $this->parent->numRows |
460 | )) |
461 | { |
462 | // @codeCoverageIgnoreStart |
463 | return; |
464 | // @codeCoverageIgnoreEnd |
465 | } |
466 | |
467 | $tokens = $this->parent->tokens[$rowNum]; |
468 | |
469 | $inComment = ($this->idx > 0 && $this->parent->rows[$this->idx - 1]->hlOpenComment); |
470 | |
471 | // Keep track of where you are in the line, so that |
472 | // multiples of the same tokens can be effectively matched |
473 | $offset = 0; |
474 | |
475 | foreach ($tokens as $token) |
476 | { |
477 | if ($offset >= $this->rsize) |
478 | { |
479 | // @codeCoverageIgnoreStart |
480 | break; |
481 | // @codeCoverageIgnoreEnd |
482 | } |
483 | |
484 | // A multi-line comment can end in the middle of a line... |
485 | if ($inComment) |
486 | { |
487 | // Try looking for the end of the comment first |
488 | $commentEnd = strpos($this->render, '*/'); |
489 | if ($commentEnd !== FALSE) |
490 | { |
491 | $inComment = FALSE; |
492 | array_replace_range($this->hl, 0, $commentEnd + 2, Highlight::ML_COMMENT); |
493 | $offset = $commentEnd; |
494 | continue; |
495 | } |
496 | |
497 | // Otherwise, just set the whole row |
498 | $this->hl = array_fill(0, $this->rsize, Highlight::ML_COMMENT); |
499 | $this->hl[$offset] = Highlight::ML_COMMENT; |
500 | break; |
501 | } |
502 | |
503 | $char = $token['char']; // ?? ''; |
504 | $charLen = strlen($char); |
505 | if ($charLen === 0 || $offset >= $this->rsize) |
506 | { |
507 | // @codeCoverageIgnoreStart |
508 | continue; |
509 | // @codeCoverageIgnoreEnd |
510 | } |
511 | $charStart = strpos($this->render, $char, $offset); |
512 | if ($charStart === FALSE) |
513 | { |
514 | continue; |
515 | } |
516 | $charEnd = $charStart + $charLen; |
517 | |
518 | // Start of multiline comment/single line comment |
519 | if (in_array($token['type'], [T_DOC_COMMENT, T_COMMENT], TRUE)) |
520 | { |
521 | // Single line comments |
522 | if (str_contains($char, '//') || str_contains($char, '#')) |
523 | { |
524 | array_replace_range($this->hl, $charStart, $charLen, Highlight::COMMENT); |
525 | break; |
526 | } |
527 | |
528 | // Start of multi-line comment |
529 | $start = strpos($this->render, '/*', $offset); |
530 | $end = strpos($this->render, '*/', $offset); |
531 | $hasStart = $start !== FALSE; |
532 | $hasEnd = $end !== FALSE; |
533 | |
534 | if ($hasStart) |
535 | { |
536 | if ($hasEnd) |
537 | { |
538 | $len = $end - $start + 2; |
539 | array_replace_range($this->hl, $start, $len, Highlight::ML_COMMENT); |
540 | $inComment = FALSE; |
541 | } |
542 | else |
543 | { |
544 | $inComment = TRUE; |
545 | array_replace_range($this->hl, $start, $charLen - $offset, Highlight::ML_COMMENT); |
546 | $offset = $start + $charLen - $offset; |
547 | } |
548 | } |
549 | |
550 | if ($inComment) |
551 | { |
552 | break; |
553 | } |
554 | } |
555 | |
556 | if (array_key_exists($token['type'], $this->phpTokenHighlightMap)) |
557 | { |
558 | $hl = $this->phpTokenHighlightMap[$token['type']]; |
559 | array_replace_range($this->hl, $charStart, $charLen, $hl); |
560 | $offset = $charEnd; |
561 | continue; |
562 | } |
563 | |
564 | // Types/identifiers/keywords that don't have their own token |
565 | if (in_array($token['char'], $this->parent->syntax->keywords2, TRUE)) |
566 | { |
567 | array_replace_range($this->hl, $charStart, $charLen, Highlight::KEYWORD2); |
568 | $offset = $charEnd; |
569 | continue; |
570 | } |
571 | |
572 | // Highlight raw characters |
573 | if (array_key_exists(trim($token['char']), $this->phpCharacterHighlightMap)) |
574 | { |
575 | $hl = $this->phpCharacterHighlightMap[trim($token['char'])]; |
576 | array_replace_range($this->hl, $charStart, $charLen, $hl); |
577 | $offset = $charEnd; |
578 | continue; |
579 | } |
580 | } |
581 | |
582 | $changed = $this->hlOpenComment !== $inComment; |
583 | $this->hlOpenComment = $inComment; |
584 | if ($changed && $this->idx + 1 < $this->parent->numRows) |
585 | { |
586 | // @codeCoverageIgnoreStart |
587 | $this->parent->rows[$this->idx + 1]->updateSyntax(); |
588 | // @codeCoverageIgnoreEnd |
589 | } |
590 | } |
591 | } |