Simplify code with match statements
Some checks failed
timw4mail/php-kilo/pipeline/head There was a failure building this commit
Some checks failed
timw4mail/php-kilo/pipeline/head There was a failure building this commit
This commit is contained in:
parent
9280b77d1e
commit
02259f61a7
@ -1,6 +1,6 @@
|
||||
FROM php:7.4-cli-alpine
|
||||
FROM php:8-cli-alpine
|
||||
|
||||
RUN apk add --no-cache --virtual .persistent-deps libffi-dev \
|
||||
&& docker-php-ext-configure ffi --with-ffi \
|
||||
&& docker-php-ext-install ffi \
|
||||
&& apk add --no-cache php7-phpdbg
|
||||
&& apk add --no-cache php8-phpdbg
|
||||
|
@ -110,7 +110,7 @@ class ANSI {
|
||||
* @param mixed ...$args
|
||||
* @return string
|
||||
*/
|
||||
private static function seq(string $pattern, ...$args): string
|
||||
private static function seq(string $pattern, mixed ...$args): string
|
||||
{
|
||||
return sprintf("\e[{$pattern}", ...$args);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use Aviat\Kilo\Tokens\PHP8;
|
||||
|
||||
/**
|
||||
* // Don't highlight this!
|
||||
* @property-read int numRows
|
||||
* @property-read int $numRows
|
||||
*/
|
||||
class Editor {
|
||||
use Traits\MagicProperties;
|
||||
@ -904,12 +904,12 @@ class Editor {
|
||||
protected function refreshSyntax(): void
|
||||
{
|
||||
// Update the syntax highlighting for all the rows of the file
|
||||
array_walk($this->rows, static fn (Row $row) => $row->updateSyntax());
|
||||
// array_walk($this->rows, static fn (Row $row) => $row->updateSyntax());
|
||||
}
|
||||
|
||||
private function refreshPHPSyntax(): void
|
||||
{
|
||||
if ($this->syntax->filetype !== 'PHP')
|
||||
if ($this->syntax?->filetype !== 'PHP')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
219
src/Row.php
219
src/Row.php
@ -6,8 +6,8 @@ use Aviat\Kilo\Enum\Highlight;
|
||||
use Aviat\Kilo\Enum\KeyCode;
|
||||
|
||||
/**
|
||||
* @property-read int size
|
||||
* @property-read int rsize
|
||||
* @property-read int $size
|
||||
* @property-read int $rsize
|
||||
*/
|
||||
class Row {
|
||||
use Traits\MagicProperties;
|
||||
@ -25,173 +25,6 @@ class Row {
|
||||
|
||||
private const T_RAW = -1;
|
||||
|
||||
private array $phpTokenHighlightMap = [
|
||||
// Delimiters
|
||||
T_ARRAY => Highlight::DELIMITER,
|
||||
T_CURLY_OPEN => Highlight::DELIMITER,
|
||||
T_DOLLAR_OPEN_CURLY_BRACES => Highlight::DELIMITER,
|
||||
T_OPEN_TAG => Highlight::DELIMITER,
|
||||
T_OPEN_TAG_WITH_ECHO => Highlight::DELIMITER,
|
||||
T_CLOSE_TAG => Highlight::DELIMITER,
|
||||
T_START_HEREDOC => Highlight::DELIMITER,
|
||||
T_END_HEREDOC => Highlight::DELIMITER,
|
||||
|
||||
// Number literals and magic constants
|
||||
T_DIR => Highlight::NUMBER,
|
||||
T_TRAIT_C => Highlight::NUMBER,
|
||||
T_DNUMBER => Highlight::NUMBER,
|
||||
T_LNUMBER => Highlight::NUMBER,
|
||||
|
||||
// String literals
|
||||
T_CONSTANT_ENCAPSED_STRING => Highlight::STRING,
|
||||
T_ENCAPSED_AND_WHITESPACE => Highlight::STRING,
|
||||
|
||||
// Simple variables
|
||||
T_VARIABLE => Highlight::VARIABLE,
|
||||
T_STRING_VARNAME => Highlight::VARIABLE,
|
||||
|
||||
// Operators
|
||||
T_AS => Highlight::OPERATOR,
|
||||
T_AND_EQUAL => Highlight::OPERATOR,
|
||||
T_BOOLEAN_AND => Highlight::OPERATOR,
|
||||
T_BOOLEAN_OR => Highlight::OPERATOR,
|
||||
T_COALESCE => Highlight::OPERATOR,
|
||||
T_CONCAT_EQUAL => Highlight::OPERATOR,
|
||||
T_DEC => Highlight::OPERATOR,
|
||||
T_DIV_EQUAL => Highlight::OPERATOR,
|
||||
T_DOUBLE_ARROW => Highlight::OPERATOR,
|
||||
T_DOUBLE_COLON => Highlight::OPERATOR,
|
||||
T_ELLIPSIS => Highlight::OPERATOR,
|
||||
T_INC => Highlight::OPERATOR,
|
||||
T_IS_EQUAL => Highlight::OPERATOR,
|
||||
T_IS_GREATER_OR_EQUAL => Highlight::OPERATOR,
|
||||
T_IS_IDENTICAL => Highlight::OPERATOR,
|
||||
T_IS_NOT_EQUAL => Highlight::OPERATOR,
|
||||
T_IS_NOT_IDENTICAL => Highlight::OPERATOR,
|
||||
T_IS_SMALLER_OR_EQUAL => Highlight::OPERATOR,
|
||||
T_SPACESHIP => Highlight::OPERATOR,
|
||||
T_LOGICAL_AND => Highlight::OPERATOR,
|
||||
T_LOGICAL_OR => Highlight::OPERATOR,
|
||||
T_LOGICAL_XOR => Highlight::OPERATOR,
|
||||
T_MINUS_EQUAL => Highlight::OPERATOR,
|
||||
T_MOD_EQUAL => Highlight::OPERATOR,
|
||||
T_MUL_EQUAL => Highlight::OPERATOR,
|
||||
T_NS_SEPARATOR => Highlight::OPERATOR,
|
||||
T_NULLSAFE_OBJECT_OPERATOR => Highlight::OPERATOR,
|
||||
T_OBJECT_OPERATOR => Highlight::OPERATOR,
|
||||
T_OR_EQUAL => Highlight::OPERATOR,
|
||||
T_PLUS_EQUAL => Highlight::OPERATOR,
|
||||
T_POW => Highlight::OPERATOR,
|
||||
T_POW_EQUAL => Highlight::OPERATOR,
|
||||
T_SL => Highlight::OPERATOR,
|
||||
T_SL_EQUAL => Highlight::OPERATOR,
|
||||
T_SR => Highlight::OPERATOR,
|
||||
T_SR_EQUAL => Highlight::OPERATOR,
|
||||
T_XOR_EQUAL => Highlight::OPERATOR,
|
||||
|
||||
// Keywords1
|
||||
T_ABSTRACT => Highlight::KEYWORD1,
|
||||
T_AS => Highlight::KEYWORD1,
|
||||
T_BREAK => Highlight::KEYWORD1,
|
||||
T_CASE => Highlight::KEYWORD1,
|
||||
T_CATCH => Highlight::KEYWORD1,
|
||||
T_CLASS => Highlight::KEYWORD1,
|
||||
T_CLONE => Highlight::KEYWORD1,
|
||||
T_CONST => Highlight::KEYWORD1,
|
||||
T_CONTINUE => Highlight::KEYWORD1,
|
||||
T_DECLARE => Highlight::KEYWORD1,
|
||||
T_DEFAULT => Highlight::KEYWORD1,
|
||||
T_DO => Highlight::KEYWORD1,
|
||||
T_ELSE => Highlight::KEYWORD1,
|
||||
T_ELSEIF => Highlight::KEYWORD1,
|
||||
T_ENDDECLARE => Highlight::KEYWORD1,
|
||||
T_ENDFOR => Highlight::KEYWORD1,
|
||||
T_ENDFOREACH => Highlight::KEYWORD1,
|
||||
T_ENDIF => Highlight::KEYWORD1,
|
||||
T_ENDSWITCH => Highlight::KEYWORD1,
|
||||
T_ENDWHILE => Highlight::KEYWORD1,
|
||||
T_EXIT => Highlight::KEYWORD1,
|
||||
T_EXTENDS => Highlight::KEYWORD1,
|
||||
T_FINAL => Highlight::KEYWORD1,
|
||||
T_FINALLY => Highlight::KEYWORD1,
|
||||
T_FN => Highlight::KEYWORD1,
|
||||
T_FOR => Highlight::KEYWORD1,
|
||||
T_FOREACH => Highlight::KEYWORD1,
|
||||
T_FUNCTION => Highlight::KEYWORD1,
|
||||
T_GLOBAL => Highlight::KEYWORD1,
|
||||
T_GOTO => Highlight::KEYWORD1,
|
||||
T_HALT_COMPILER => Highlight::KEYWORD1,
|
||||
T_IF => Highlight::KEYWORD1,
|
||||
T_IMPLEMENTS => Highlight::KEYWORD1,
|
||||
T_INSTANCEOF => Highlight::KEYWORD1,
|
||||
T_INSTEADOF => Highlight::KEYWORD1,
|
||||
T_INTERFACE => Highlight::KEYWORD1,
|
||||
T_NAMESPACE => Highlight::KEYWORD1,
|
||||
T_MATCH => Highlight::KEYWORD1,
|
||||
T_NEW => Highlight::KEYWORD1,
|
||||
T_PRIVATE => Highlight::KEYWORD1,
|
||||
T_PUBLIC => Highlight::KEYWORD1,
|
||||
T_PROTECTED => Highlight::KEYWORD1,
|
||||
T_RETURN => Highlight::KEYWORD1,
|
||||
T_STATIC => Highlight::KEYWORD1,
|
||||
T_SWITCH => Highlight::KEYWORD1,
|
||||
T_THROW => Highlight::KEYWORD1,
|
||||
T_TRAIT => Highlight::KEYWORD1,
|
||||
T_TRY => Highlight::KEYWORD1,
|
||||
T_USE => Highlight::KEYWORD1,
|
||||
T_VAR => Highlight::KEYWORD1,
|
||||
T_WHILE => Highlight::KEYWORD1,
|
||||
T_YIELD => Highlight::KEYWORD1,
|
||||
T_YIELD_FROM => Highlight::KEYWORD1,
|
||||
|
||||
// Not string literals, but identifiers, keywords, etc.
|
||||
// T_STRING => Highlight::KEYWORD2,
|
||||
|
||||
// Types and casts
|
||||
T_ARRAY_CAST => Highlight::KEYWORD2,
|
||||
T_BOOL_CAST => Highlight::KEYWORD2,
|
||||
T_CALLABLE => Highlight::KEYWORD2,
|
||||
T_DOUBLE_CAST => Highlight::KEYWORD2,
|
||||
T_INT_CAST => Highlight::KEYWORD2,
|
||||
T_OBJECT_CAST => Highlight::KEYWORD2,
|
||||
T_STRING_CAST => Highlight::KEYWORD2,
|
||||
T_UNSET_CAST => Highlight::KEYWORD2,
|
||||
|
||||
// Invalid syntax
|
||||
T_BAD_CHARACTER => Highlight::INVALID,
|
||||
];
|
||||
|
||||
private array $phpCharacterHighlightMap = [
|
||||
// Delimiter characters
|
||||
'[' => Highlight::DELIMITER,
|
||||
']' => Highlight::DELIMITER,
|
||||
'{' => Highlight::DELIMITER,
|
||||
'}' => Highlight::DELIMITER,
|
||||
'(' => Highlight::DELIMITER,
|
||||
')' => Highlight::DELIMITER,
|
||||
'"' => Highlight::DELIMITER,
|
||||
"'" => Highlight::DELIMITER,
|
||||
|
||||
// Single character operators
|
||||
'?' => Highlight::OPERATOR,
|
||||
',' => Highlight::OPERATOR,
|
||||
';' => Highlight::OPERATOR,
|
||||
':' => Highlight::OPERATOR,
|
||||
'^' => Highlight::OPERATOR,
|
||||
'%' => Highlight::OPERATOR,
|
||||
'+' => Highlight::OPERATOR,
|
||||
'-' => Highlight::OPERATOR,
|
||||
'*' => Highlight::OPERATOR,
|
||||
'/' => Highlight::OPERATOR,
|
||||
'.' => Highlight::OPERATOR,
|
||||
'|' => Highlight::OPERATOR,
|
||||
'~' => Highlight::OPERATOR,
|
||||
'>' => Highlight::OPERATOR,
|
||||
'<' => Highlight::OPERATOR,
|
||||
'=' => Highlight::OPERATOR,
|
||||
'!' => Highlight::OPERATOR,
|
||||
];
|
||||
|
||||
public static function new(Editor $parent, string $chars, int $idx): self
|
||||
{
|
||||
$self = new self();
|
||||
@ -204,7 +37,7 @@ class Row {
|
||||
|
||||
private function __construct() {}
|
||||
|
||||
public function __get(string $name)
|
||||
public function __get(string $name): mixed
|
||||
{
|
||||
return match ($name)
|
||||
{
|
||||
@ -215,9 +48,9 @@ class Row {
|
||||
};
|
||||
}
|
||||
|
||||
public function __set(string $key, mixed $value): void
|
||||
public function __set(string $name, mixed $value): void
|
||||
{
|
||||
if ($key === 'chars')
|
||||
if ($name === 'chars')
|
||||
{
|
||||
$this->chars = $value;
|
||||
$this->update();
|
||||
@ -553,35 +386,35 @@ class Row {
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($token['type'], $this->phpTokenHighlightMap))
|
||||
$tokenHighlight = php_token_to_highlight($token['type']);
|
||||
$charHighlight = php_char_to_highlight(trim($token['char']));
|
||||
|
||||
$hl = match(true) {
|
||||
// Matches a predefined PHP token
|
||||
$token['type'] !== self::T_RAW && $tokenHighlight !== Highlight::NORMAL
|
||||
=> $tokenHighlight,
|
||||
|
||||
// Matches a specific syntax character
|
||||
$charHighlight !== Highlight::NORMAL => $charHighlight,
|
||||
|
||||
// Types/identifiers/keywords that don't have their own token, but are
|
||||
// defined as keywords
|
||||
in_array($token['char'], $this->parent->syntax->keywords2 ?? [], TRUE)
|
||||
=> Highlight::KEYWORD2,
|
||||
|
||||
default => Highlight::NORMAL,
|
||||
};
|
||||
|
||||
if ($hl !== Highlight::NORMAL)
|
||||
{
|
||||
$hl = $this->phpTokenHighlightMap[$token['type']];
|
||||
array_replace_range($this->hl, $charStart, $charLen, $hl);
|
||||
$offset = $charEnd;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Types/identifiers/keywords that don't have their own token
|
||||
if (in_array($token['char'], $this->parent->syntax->keywords2, TRUE))
|
||||
{
|
||||
array_replace_range($this->hl, $charStart, $charLen, Highlight::KEYWORD2);
|
||||
$offset = $charEnd;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Highlight raw characters
|
||||
if (array_key_exists(trim($token['char']), $this->phpCharacterHighlightMap))
|
||||
{
|
||||
$hl = $this->phpCharacterHighlightMap[trim($token['char'])];
|
||||
array_replace_range($this->hl, $charStart, $charLen, $hl);
|
||||
$offset = $charEnd;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$changed = $this->hlOpenComment !== $inComment;
|
||||
$this->hlOpenComment = $inComment;
|
||||
if ($changed && $this->idx + 1 < $this->parent->numRows)
|
||||
if ($changed && ($this->idx + 1) < $this->parent->numRows)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
$this->parent->rows[$this->idx + 1]->updateSyntax();
|
||||
|
@ -17,7 +17,13 @@ class Termios {
|
||||
{
|
||||
$ffi = get_ffi();
|
||||
$termios = $ffi->new('struct termios');
|
||||
$res = $ffi->tcgetattr(C::STDIN_FILENO, FFI::addr($termios));
|
||||
if ($termios === NULL)
|
||||
{
|
||||
throw new TermiosException('Failed to create termios struct');
|
||||
}
|
||||
|
||||
$termiosAddr = FFI::addr($termios);
|
||||
$res = $ffi->tcgetattr(C::STDIN_FILENO, $termiosAddr);
|
||||
|
||||
if ($res === -1)
|
||||
{
|
||||
|
@ -1,185 +0,0 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Aviat\Kilo\Tokens;
|
||||
|
||||
use PhpToken;
|
||||
|
||||
use function Aviat\Kilo\str_contains;
|
||||
use function Aviat\Kilo\tabs_to_spaces;
|
||||
|
||||
class PHP {
|
||||
|
||||
private string $code;
|
||||
|
||||
private array $rawLines;
|
||||
|
||||
private array $tokens;
|
||||
|
||||
private int $lineNum = 1;
|
||||
|
||||
private function __construct(string $code)
|
||||
{
|
||||
$lines = explode("\n", $code);
|
||||
array_unshift($lines, '');
|
||||
unset($lines[0]);
|
||||
|
||||
$this->code = $code;
|
||||
$this->rawLines = $lines;
|
||||
$this->tokens = array_fill(1, count($lines), []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use 'token_get_all' to get the tokens for a file,
|
||||
* organized by row number
|
||||
*
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
public static function getTokens(string $code): array
|
||||
{
|
||||
return (new self($code))->organizeTokens();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return tokens for the current $filename, organized
|
||||
* by row number
|
||||
*
|
||||
* @param string $filename
|
||||
* @return array
|
||||
*/
|
||||
public static function getFileTokens(string $filename): array
|
||||
{
|
||||
$code = @file_get_contents($filename);
|
||||
|
||||
if ($code === FALSE)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
return self::getTokens($code);
|
||||
}
|
||||
|
||||
protected function organizeTokens(): array
|
||||
{
|
||||
$rawTokens = (class_exists('PhpToken'))
|
||||
? \PhpToken::tokenize($this->code)
|
||||
: token_get_all($this->code);
|
||||
foreach ($rawTokens as $t)
|
||||
{
|
||||
if ($t instanceof \PhpToken)
|
||||
{
|
||||
$this->processObjectToken($t);
|
||||
}
|
||||
else if (is_array($t))
|
||||
{
|
||||
$this->processArrayToken($t);
|
||||
}
|
||||
else if (is_string($t))
|
||||
{
|
||||
$this->processStringToken($t);
|
||||
}
|
||||
}
|
||||
|
||||
ksort($this->tokens);
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
protected function processObjectToken(\PhpToken $token): void
|
||||
{
|
||||
$currentLine = $token->line;
|
||||
$char = tabs_to_spaces($token->text);
|
||||
|
||||
$current = [
|
||||
'type' => $token->id,
|
||||
'typeName' => $token->getTokenName(),
|
||||
'char' => $char,
|
||||
'line' => $currentLine,
|
||||
];
|
||||
|
||||
$this->tokens[$currentLine][] = $current;
|
||||
}
|
||||
|
||||
protected function processArrayToken(array $token): void
|
||||
{
|
||||
[$type, $rawChar, $currentLine] = $token;
|
||||
$char = tabs_to_spaces($rawChar);
|
||||
|
||||
$this->lineNum = $currentLine;
|
||||
|
||||
$current = [
|
||||
'type' => $type,
|
||||
'typeName' => token_name($type),
|
||||
'char' => $char,
|
||||
'line' => $currentLine,
|
||||
];
|
||||
|
||||
// Single new line, or starts with a new line with other whitespace
|
||||
if (str_starts_with($char, "\n") && trim($char) === '')
|
||||
{
|
||||
$this->tokens[$this->lineNum][] = $current;
|
||||
$this->lineNum++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Only return the first line of a multi-line token for this line array
|
||||
if (str_contains($char, "\n"))
|
||||
{
|
||||
$chars = explode("\n", $char);
|
||||
$current['original'] = [
|
||||
'string' => $char,
|
||||
'lines' => $chars,
|
||||
];
|
||||
$current['char'] = array_shift($chars);
|
||||
|
||||
// Add new lines for additional newline characters
|
||||
$nextLine = $currentLine;
|
||||
foreach ($chars as $char)
|
||||
{
|
||||
$nextLine++;
|
||||
|
||||
if ( ! empty($char))
|
||||
{
|
||||
$this->processStringToken($char, $nextLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->tokens[$this->lineNum][] = $current;
|
||||
}
|
||||
|
||||
protected function processStringToken(string $token, ?int $startLine = NULL): void
|
||||
{
|
||||
$char = tabs_to_spaces($token);
|
||||
|
||||
$startLine = $startLine ?? $this->lineNum;
|
||||
$lineNumber = $this->findCorrectLine($char, $startLine) ?? $startLine;
|
||||
|
||||
// Simple characters, usually delimiters or single character operators
|
||||
$this->tokens[$lineNumber][] = [
|
||||
'type' => -1,
|
||||
'typeName' => 'RAW',
|
||||
'char' => tabs_to_spaces($token),
|
||||
];
|
||||
}
|
||||
|
||||
private function findCorrectLine(string $search, int $rowOffset, int $searchLength = 5): ?int
|
||||
{
|
||||
$end = $rowOffset + $searchLength;
|
||||
if ($end > count($this->rawLines))
|
||||
{
|
||||
$end = count($this->rawLines);
|
||||
}
|
||||
|
||||
for ($i = $rowOffset; $i < $end; $i++)
|
||||
{
|
||||
if (str_contains($this->rawLines[$i], $search))
|
||||
{
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
@ -27,7 +27,6 @@ class PHP8 extends PhpToken {
|
||||
|
||||
$self = (new self(0, $code));
|
||||
|
||||
// $->code = $code;
|
||||
$self->rawLines = $lines;
|
||||
$self->tokens = array_fill(1, count($lines), []);
|
||||
|
||||
@ -78,6 +77,71 @@ class PHP8 extends PhpToken {
|
||||
'line' => $currentLine,
|
||||
];
|
||||
|
||||
// Single new line, or starts with a new line with other whitespace
|
||||
if (str_starts_with($char, "\n") && trim($char) === '')
|
||||
{
|
||||
$this->tokens[$currentLine][] = $current;
|
||||
// $this->lineNum++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Only return the first line of a multi-line token for this line array
|
||||
if (str_contains($char, "\n"))
|
||||
{
|
||||
$chars = explode("\n", $char);
|
||||
$current['original'] = [
|
||||
'string' => $char,
|
||||
'lines' => $chars,
|
||||
];
|
||||
$current['char'] = array_shift($chars);
|
||||
|
||||
// Add new lines for additional newline characters
|
||||
$nextLine = $currentLine;
|
||||
foreach ($chars as $char)
|
||||
{
|
||||
$nextLine++;
|
||||
|
||||
if ( ! empty($char))
|
||||
{
|
||||
$this->processStringToken($char, $nextLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->tokens[$currentLine][] = $current;
|
||||
}
|
||||
|
||||
protected function processStringToken(string $token, int $startLine): void
|
||||
{
|
||||
$char = tabs_to_spaces($token);
|
||||
$lineNumber = $this->findCorrectLine($char, $startLine) ?? $startLine;
|
||||
|
||||
// Simple characters, usually delimiters or single character operators
|
||||
$this->tokens[$lineNumber][] = [
|
||||
'type' => -1,
|
||||
'typeName' => 'RAW',
|
||||
'char' => tabs_to_spaces($token),
|
||||
'line' => $lineNumber,
|
||||
];
|
||||
}
|
||||
|
||||
private function findCorrectLine(string $search, int $rowOffset, int $searchLength = 5): ?int
|
||||
{
|
||||
$end = $rowOffset + $searchLength;
|
||||
if ($end > count($this->rawLines))
|
||||
{
|
||||
$end = count($this->rawLines);
|
||||
}
|
||||
|
||||
for ($i = $rowOffset; $i < $end; $i++)
|
||||
{
|
||||
if (str_contains($this->rawLines[$i], $search))
|
||||
{
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
@ -14,7 +14,13 @@ use Aviat\Kilo\Enum\{C, Color, Highlight, KeyCode};
|
||||
*/
|
||||
function has_tput(): bool
|
||||
{
|
||||
return str_contains(shell_exec('type tput'), ' is ');
|
||||
$cmd = shell_exec('type tput');
|
||||
if ( ! is_string($cmd))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return str_contains($cmd, ' is ');
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -126,15 +132,16 @@ function is_digit(string $char): bool
|
||||
*/
|
||||
function is_space(string $char): bool
|
||||
{
|
||||
$ws = [
|
||||
return match($char) {
|
||||
KeyCode::CARRIAGE_RETURN,
|
||||
KeyCode::FORM_FEED,
|
||||
KeyCode::NEWLINE,
|
||||
KeyCode::SPACE,
|
||||
KeyCode::TAB,
|
||||
KeyCode::VERTICAL_TAB,
|
||||
];
|
||||
return is_ascii($char) && in_array($char, $ws, TRUE);
|
||||
KeyCode::VERTICAL_TAB
|
||||
=> true,
|
||||
default => false,
|
||||
};
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -477,3 +484,162 @@ function get_file_syntax_map(): array
|
||||
|
||||
return $db;
|
||||
}
|
||||
|
||||
function php_token_to_highlight(int $token): int
|
||||
{
|
||||
return match($token) {
|
||||
// Delimiters
|
||||
T_ARRAY,
|
||||
T_CURLY_OPEN,
|
||||
T_DOLLAR_OPEN_CURLY_BRACES,
|
||||
T_OPEN_TAG,
|
||||
T_OPEN_TAG_WITH_ECHO,
|
||||
T_CLOSE_TAG,
|
||||
T_START_HEREDOC,
|
||||
T_END_HEREDOC => Highlight::DELIMITER,
|
||||
|
||||
// Number literals and magic constants
|
||||
T_DIR,
|
||||
T_TRAIT_C,
|
||||
T_DNUMBER,
|
||||
T_LNUMBER,
|
||||
T_FILE,
|
||||
T_FUNC_C => Highlight::NUMBER,
|
||||
|
||||
// String literals
|
||||
T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE => Highlight::STRING,
|
||||
|
||||
// Simple variables
|
||||
T_VARIABLE, T_STRING_VARNAME => Highlight::VARIABLE,
|
||||
|
||||
// Operators
|
||||
T_AS,
|
||||
T_AND_EQUAL,
|
||||
T_BOOLEAN_AND,
|
||||
T_BOOLEAN_OR,
|
||||
T_COALESCE,
|
||||
T_COALESCE_EQUAL,
|
||||
T_CONCAT_EQUAL,
|
||||
T_DEC,
|
||||
T_DIV_EQUAL,
|
||||
T_DOUBLE_ARROW,
|
||||
T_DOUBLE_COLON,
|
||||
T_ELLIPSIS,
|
||||
T_INC,
|
||||
T_INSTANCEOF,
|
||||
T_INSTEADOF,
|
||||
T_IS_EQUAL,
|
||||
T_IS_GREATER_OR_EQUAL,
|
||||
T_IS_IDENTICAL,
|
||||
T_IS_NOT_EQUAL,
|
||||
T_IS_NOT_IDENTICAL,
|
||||
T_IS_SMALLER_OR_EQUAL,
|
||||
T_SPACESHIP,
|
||||
T_LOGICAL_AND,
|
||||
T_LOGICAL_OR,
|
||||
T_LOGICAL_XOR,
|
||||
T_MINUS_EQUAL,
|
||||
T_MOD_EQUAL,
|
||||
T_MUL_EQUAL,
|
||||
T_NS_SEPARATOR,
|
||||
T_NULLSAFE_OBJECT_OPERATOR,
|
||||
T_OBJECT_OPERATOR,
|
||||
T_OR_EQUAL,
|
||||
T_PLUS_EQUAL,
|
||||
T_POW,
|
||||
T_POW_EQUAL,
|
||||
T_SL,
|
||||
T_SL_EQUAL,
|
||||
T_SR,
|
||||
T_SR_EQUAL,
|
||||
T_XOR_EQUAL => Highlight::OPERATOR,
|
||||
|
||||
// Keywords1
|
||||
T_ABSTRACT,
|
||||
T_BREAK,
|
||||
T_CASE,
|
||||
T_CATCH,
|
||||
T_CLASS,
|
||||
T_CLONE,
|
||||
T_CONST,
|
||||
T_CONTINUE,
|
||||
T_DECLARE,
|
||||
T_DEFAULT,
|
||||
T_DO,
|
||||
T_ECHO,
|
||||
T_ELSE,
|
||||
T_ELSEIF,
|
||||
T_EMPTY,
|
||||
T_ENDDECLARE,
|
||||
T_ENDFOR,
|
||||
T_ENDFOREACH,
|
||||
T_ENDIF,
|
||||
T_ENDSWITCH,
|
||||
T_ENDWHILE,
|
||||
T_EVAL,
|
||||
T_EXIT,
|
||||
T_EXTENDS,
|
||||
T_FINAL,
|
||||
T_FINALLY,
|
||||
T_FN,
|
||||
T_FOR,
|
||||
T_FOREACH,
|
||||
T_FUNCTION,
|
||||
T_GLOBAL,
|
||||
T_GOTO,
|
||||
T_HALT_COMPILER,
|
||||
T_IF,
|
||||
T_IMPLEMENTS,
|
||||
T_INCLUDE,
|
||||
T_INCLUDE_ONCE,
|
||||
T_INTERFACE,
|
||||
T_NAMESPACE,
|
||||
T_MATCH,
|
||||
T_NEW,
|
||||
T_PRIVATE,
|
||||
T_PUBLIC,
|
||||
T_PROTECTED,
|
||||
T_RETURN,
|
||||
T_STATIC,
|
||||
T_SWITCH,
|
||||
T_THROW,
|
||||
T_TRAIT,
|
||||
T_TRY,
|
||||
T_USE,
|
||||
T_VAR,
|
||||
T_WHILE,
|
||||
T_YIELD,
|
||||
T_YIELD_FROM => Highlight::KEYWORD1,
|
||||
|
||||
// Not string literals, but identifiers, keywords, etc.
|
||||
// T_STRING => Highlight::KEYWORD2,
|
||||
|
||||
// Types and casts
|
||||
T_ARRAY_CAST,
|
||||
T_BOOL_CAST,
|
||||
T_CALLABLE,
|
||||
T_DOUBLE_CAST,
|
||||
T_INT_CAST,
|
||||
T_OBJECT_CAST,
|
||||
T_STRING_CAST,
|
||||
T_UNSET_CAST => Highlight::KEYWORD2,
|
||||
|
||||
// Invalid syntax
|
||||
T_BAD_CHARACTER => Highlight::INVALID,
|
||||
default => Highlight::NORMAL,
|
||||
};
|
||||
}
|
||||
|
||||
function php_char_to_highlight(string $char): int
|
||||
{
|
||||
return match ($char) {
|
||||
// Delimiter characters
|
||||
'[', ']', '{', '}', '(', ')', '"', "'" => Highlight::DELIMITER,
|
||||
|
||||
// Single character operators
|
||||
'?', ',', ';', ':', '^', '%', '+', '-',
|
||||
'*', '/', '.', '|', '~', '>', '<', '=', '!' => Highlight::OPERATOR,
|
||||
|
||||
default => Highlight::NORMAL,
|
||||
};
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ use PHPUnit\Framework\TestCase;
|
||||
class TermiosTest extends TestCase {
|
||||
public function testEnableRawMode(): void
|
||||
{
|
||||
$this->markTestSkipped();
|
||||
|
||||
// There will be an exception, due to the way the test suite is run
|
||||
$this->expectException(TermiosException::class);
|
||||
$this->assertNotEquals(NULL, Termios::enableRawMode());
|
||||
|
@ -2,15 +2,15 @@
|
||||
|
||||
namespace Aviat\Kilo\Tests\Tokens;
|
||||
|
||||
use Aviat\Kilo\Tokens\PHP;
|
||||
use Aviat\Kilo\Tokens\PHP8;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class PHPTest extends TestCase {
|
||||
class PHP8Test extends TestCase {
|
||||
public function testGetFileTokens(): void
|
||||
{
|
||||
$filename = realpath(__DIR__ . '/../../test.php');
|
||||
$file = file_get_contents($filename);
|
||||
$tokens = PHP::getFileTokens($filename);
|
||||
$tokens = PHP8::getFileTokens($filename);
|
||||
|
||||
$lines = explode("\n", $file);
|
||||
array_unshift($lines, '');
|
||||
@ -21,7 +21,7 @@ class PHPTest extends TestCase {
|
||||
public function testGetFileTokensEmptyFile(): void
|
||||
{
|
||||
$filename = __DIR__ . '/../../foobarbaz.php';
|
||||
$this->assertEmpty(PHP::getFileTokens($filename));
|
||||
$this->assertEmpty(PHP8::getFileTokens($filename));
|
||||
}
|
||||
|
||||
private function verifyTokens(array $tokens, array $lines): void
|
||||
@ -46,7 +46,7 @@ class PHPTest extends TestCase {
|
||||
$this->assertIsArray($token, 'All outputted tokens should be arrays');
|
||||
|
||||
// Make sure the matched string for the token is on the correct line
|
||||
if (strpos($lines[$index], trim($token['char'])) === FALSE)
|
||||
if ( ! str_contains($lines[$index], trim($token['char'])))
|
||||
{
|
||||
$token['misplaced_line'] = $index;
|
||||
$misplacedTokens[] = $token;
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user