php-kilo/src/Row.php

184 lines
3.2 KiB
PHP
Raw Normal View History

2019-10-24 16:57:27 -04:00
<?php declare(strict_types=1);
namespace Kilo;
/**
* @property-read int size
* @property-read int rsize
*/
class Row {
use MagicProperties;
public string $chars = '';
public string $render = '';
2019-10-25 10:28:15 -04:00
// This feels dirty...
private Editor $parent;
2019-10-24 16:57:27 -04:00
public array $hl = [];
2019-10-25 10:28:15 -04:00
public static function new(Editor $parent, string $chars): self
2019-10-24 16:57:27 -04:00
{
2019-10-25 10:28:15 -04:00
$self = new self();
$self->chars = $chars;
$self->parent = $parent;
2019-10-24 16:57:27 -04:00
2019-10-25 10:28:15 -04:00
return $self;
2019-10-24 16:57:27 -04:00
}
2019-10-25 10:28:15 -04:00
private function __construct() {}
2019-10-24 16:57:27 -04:00
public function __get(string $name)
{
switch ($name)
{
case 'size':
return strlen($this->chars);
case 'rsize':
return strlen($this->render);
default:
return NULL;
}
}
public function __toString(): string
{
return $this->chars . "\n";
}
2019-10-25 10:28:15 -04:00
public function insertChar(int $at, string $c): void
{
if ($at < 0 || $at > $this->size)
{
$at = $this->size;
}
// Safely insert into arbitrary position in the existing string
$this->chars = substr($this->chars, 0, $at) . $c . substr($this->chars, $at);
$this->update();
$this->parent->dirty++;
}
public function appendString(string $s): void
{
$this->chars .= $s;
$this->update();
$this->parent->dirty++;
}
public function deleteChar(int $at): void
{
if ($at < 0 || $at >= $this->size)
{
return;
}
$this->chars = substr_replace($this->chars, '', $at, 1);
$this->update();
$this->parent->dirty++;
}
2019-10-24 16:57:27 -04:00
public function update(): void
{
$idx = 0;
for ($i = 0; $i < $this->size; $i++)
{
if ($this->chars[$i] === "\t")
{
$this->render[$idx++] = ' ';
while ($idx % KILO_TAB_STOP !== 0)
{
$this->render[$idx++] = ' ';
}
}
else
{
$this->render[$idx++] = $this->chars[$i];
}
}
$this->updateSyntax();
}
// ------------------------------------------------------------------------
// ! Syntax Highlighting
// ------------------------------------------------------------------------
protected function updateSyntax(): void
{
$this->hl = array_fill(0, $this->rsize, Highlight::NORMAL);
$prevSep = TRUE;
2019-10-25 11:49:04 -04:00
$inString = '';
2019-10-24 16:57:27 -04:00
$i = 0;
while ($i < $this->rsize)
{
$char = $this->render[$i];
$prevHl = ($i > 0) ? $this->hl[$i - 1] : Highlight::NORMAL;
2019-10-25 10:28:15 -04:00
if ($this->parent->syntax === NULL)
{
return;
}
2019-10-25 11:49:04 -04:00
if ($this->parent->syntax->flags & Syntax::HIGHLIGHT_STRINGS)
{
if ($inString !== '')
{
$this->hl[$i] = Highlight::STRING;
// Check for escaped character
if ($char === '\\' && $i+1 < $this->rsize)
{
$this->hl[$i + 1] = Highlight::STRING;
$i += 2;
continue;
}
if ($char === $inString)
{
$inString = '';
}
$i++;
$prevSep = 1;
continue;
}
if ( $char === '""' || $char === '\'')
{
$inString = $char;
$this->hl[$i] = Highlight::STRING;
$i++;
continue;
}
}
2019-10-25 10:28:15 -04:00
if ($this->parent->syntax->flags & Syntax::HIGHLIGHT_NUMBERS)
2019-10-24 16:57:27 -04:00
{
2019-10-25 10:28:15 -04:00
// Numbers, including decimal points
if (
($char === '.' && $prevHl === Highlight::NUMBER) ||
(($prevSep || $prevHl === Highlight::NUMBER) && is_digit($char))
)
{
$this->hl[$i] = Highlight::NUMBER;
$i++;
$prevSep = FALSE;
continue;
}
2019-10-24 16:57:27 -04:00
}
$prevSep = is_separator($char);
$i++;
}
}
}