From dcaf9227968545f304e8666927bea94d23a6d0fd Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Fri, 9 Apr 2021 19:41:15 -0400 Subject: [PATCH] Split syntax highlighting into methods --- src/Row.php | 227 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 161 insertions(+), 66 deletions(-) diff --git a/src/Row.php b/src/Row.php index 85a2da8..6e27748 100644 --- a/src/Row.php +++ b/src/Row.php @@ -155,26 +155,168 @@ class Row { $this->highlightGeneral(); } - protected function highlightComment(int $i, string $char): bool + protected function highlightNumber(int &$i, Syntax $opts): bool { - $scs = $this->parent->fileType->syntax->singleLineCommentStart; - $scsLen = strlen($scs); - - if ($scsLen > 0 && substr($this->render, $i, $scsLen) === $scs) + $char = $this->render[$i]; + if ($opts->numbers() && is_digit($char)) { - array_replace_range($this->hl, $i, $this->rsize - $i, Highlight::COMMENT); + if ($i > 0) + { + $prevChar = $this->render[$i - 1]; + if ( ! is_separator($prevChar)) + { + return false; + } + } + + while (true) + { + $this->hl[$i] = Highlight::NUMBER; + $i++; + + if ($i < strlen($this->render)) + { + $nextChar = $this->render[$i]; + if ($nextChar !== '.' && ! is_digit($nextChar)) + { + break; + } + } + else + { + break; + } + } + return true; } return false; } - protected function highlightString(int &$i): bool + protected function highlightWord(int &$i, array $keywords, int $syntaxType): bool + { + if ($i > 0) + { + $prevChar = $this->render[$i - 1]; + if ( ! is_separator($prevChar)) + { + return false; + } + } + + foreach ($keywords as $k) + { + $klen = strlen($k); + $nextCharOffset = $i + $klen; + $isEndOfLine = $nextCharOffset >= $this->rsize; + $nextChar = ($isEndOfLine) ? RawKeyCode::NULL : $this->render[$nextCharOffset]; + + if (substr($this->render, $i, $klen) === $k && is_separator($nextChar)) + { + array_replace_range($this->hl, $i, $klen, $syntaxType); + $i += $klen - 1; + + return true; + } + } + + return false; + } + + protected function highlightPrimaryKeywords(int &$i, Syntax $opts): bool + { + return $this->highlightWord($i, $opts->keywords1, Highlight::KEYWORD1); + } + + protected function highlightSecondaryKeywords(int &$i, Syntax $opts): bool + { + return $this->highlightWord($i, $opts->keywords2, Highlight::KEYWORD2); + } + + protected function highlightChar(int &$i, Syntax $opts): bool { $char = $this->render[$i]; - $enabled = $this->parent->fileType->syntax->flags & Syntax::HIGHLIGHT_STRINGS; - if ($enabled && $char === '"' || $char === '\'') + if ($opts->characters() && $char === "'") + { + $nextChar = $this->render[$i + 1]; + $closingIndex = ($nextChar === '\\') ? $i + 3 : $i + 2; + + $closingChar = $this->render[$closingIndex]; + if ($closingChar === "'") + { + array_replace_range($this->hl, $i, $closingIndex, Highlight::CHARACTER); + $i = $closingIndex; + + return true; + } + } + + return false; + } + + protected function highlightComment(int &$i, Syntax $opts): bool + { + if ( ! $opts->comments()) + { + return false; + } + + $scs = $opts->singleLineCommentStart; + $scsLen = strlen($scs); + + if ($scsLen > 0 && substr($this->render, $i, $scsLen) === $scs) + { + array_replace_range($this->hl, $i, $this->rsize - $i, Highlight::COMMENT); + $i = $this->rsize; + + return true; + } + + return false; + } + + protected function highlightMultilineComments(int &$i, Syntax $opts): bool + { + if ( ! $opts->comments()) + { + return false; + } + + $mcs = $opts->multiLineCommentStart; + $mce = $opts->multiLineCommentEnd; + + $mcsLen = strlen($mcs); + $mceLen = strlen($mce); + + if ($i + $mcsLen < $this->rsize && \str_contains($this->render, $mcs)) + { + $endix = strpos($this->render, $mcs); + $closingIndex = ($endix !== false) + ? $i + $endix + $mcsLen + $mceLen + : $this->rsize; + + array_replace_range($this->hl, $i, $closingIndex, Highlight::ML_COMMENT); + $i += $closingIndex; + + return true; + } + + return false; + } + + protected function highlightString(int &$i, Syntax $opts): bool + { + $char = $this->render[$i]; + + // If there's a separate character type, highlight that separately + if ($opts->hasChar() && $char === "'") + { + return false; + } + + if ($opts->strings() && $char === '"' || $char === '\'') { $quote = $char; $this->hl[$i] = Highlight::STRING; @@ -221,18 +363,12 @@ class Row { $syntax = $this->parent->fileType->syntax; - $keywords1 = $syntax->keywords1; - $keywords2 = $syntax->keywords2; - - $scs = $syntax->singleLineCommentStart; $mcs = $syntax->multiLineCommentStart; $mce = $syntax->multiLineCommentEnd; - $scsLen = strlen($scs); $mcsLen = strlen($mcs); $mceLen = strlen($mce); - $prevSep = TRUE; $inString = ''; $inComment = ($this->idx > 0 && $this->parent->rows[$this->idx - 1]->hlOpenComment); @@ -243,14 +379,6 @@ class Row { $char = $this->render[$i]; $prevHl = ($i > 0) ? $this->hl[$i - 1] : Highlight::NORMAL; - // Single-line comments - if ($scsLen > 0 && $inString === '' && $inComment === FALSE - && substr($this->render, $i, $scsLen) === $scs) - { - array_replace_range($this->hl, $i, $this->rsize - $i, Highlight::COMMENT); - break; - } - // Multi-line comments if ($mcsLen > 0 && $mceLen > 0 && $inString === '') { @@ -262,7 +390,6 @@ class Row { array_replace_range($this->hl, $i, $mceLen, Highlight::ML_COMMENT); $i += $mceLen; $inComment = FALSE; - $prevSep = TRUE; continue; } @@ -279,50 +406,18 @@ class Row { } } - // String/Char literals - $this->highlightString($i); - - // Numbers, including decimal points - if ($syntax->flags & Syntax::HIGHLIGHT_NUMBERS) - { - if ( - ($char === '.' && $prevHl === Highlight::NUMBER) || - (($prevSep || $prevHl === Highlight::NUMBER) && is_digit($char)) - ) - { - $this->hl[$i] = Highlight::NUMBER; - $i++; - $prevSep = FALSE; - continue; - } + if ( + $this->highlightChar($i, $syntax) + || $this->highlightComment($i, $syntax) + || $this->highlightMultilineComments($i, $syntax) + || $this->highlightPrimaryKeywords($i, $syntax) + || $this->highlightSecondaryKeywords($i, $syntax) + || $this->highlightString($i, $syntax) + || $this->highlightNumber($i, $syntax) + ) { + continue; } - // Keywords - if ($prevSep) - { - $findKeywords = function (array $keywords, int $syntaxType) use (&$i): void - { - foreach ($keywords as $k) - { - $klen = strlen($k); - $nextCharOffset = $i + $klen; - $isEndOfLine = $nextCharOffset >= $this->rsize; - $nextChar = ($isEndOfLine) ? RawKeyCode::NULL : $this->render[$nextCharOffset]; - - if (substr($this->render, $i, $klen) === $k && is_separator($nextChar)) - { - array_replace_range($this->hl, $i, $klen, $syntaxType); - $i += $klen - 1; - break; - } - } - }; - - $findKeywords($keywords1, Highlight::KEYWORD1); - $findKeywords($keywords2, Highlight::KEYWORD2); - } - - $prevSep = is_separator($char); $i++; }