Split classes and setup autoloading

This commit is contained in:
Timothy Warren 2019-10-24 16:57:27 -04:00
parent 88afc3909e
commit cb8eb05249
8 changed files with 182 additions and 160 deletions

View File

@ -7,6 +7,7 @@ due to requiring the `FFI` extension.
* The `editor` prefix has been removed from all the relevant functions, instead they are methods on the `Editor` class. * The `editor` prefix has been removed from all the relevant functions, instead they are methods on the `Editor` class.
* Enums are faked with class constants * Enums are faked with class constants
* Basic PHP class auto-loading is used
* Properties that must be manually updated in the C version (like counts/string length) are implemented with magic methods, * Properties that must be manually updated in the C version (like counts/string length) are implemented with magic methods,
so they are essentially calculated on read. so they are essentially calculated on read.
* Generally, if a function exists in PHP, with the same name as the C function, the PHP version will be used. * Generally, if a function exists in PHP, with the same name as the C function, the PHP version will be used.

11
kilo
View File

@ -10,9 +10,16 @@ define('KILO_VERSION', '0.0.1');
define('KILO_TAB_STOP', 4); define('KILO_TAB_STOP', 4);
define('KILO_QUIT_TIMES', 3); define('KILO_QUIT_TIMES', 3);
require_once __DIR__ . '/src/C.php'; // Set up autoloading
require_once __DIR__ . '/src/functions.php'; require_once __DIR__ . '/src/functions.php';
require_once __DIR__ . '/src/Editor.php'; spl_autoload_register(static function ($class) {
$parts = explode('\\', $class);
$file = __DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $parts[1] . '.php';
if (file_exists($file))
{
require_once $file;
}
});
function main(int $argc, array $argv): int function main(int $argc, array $argv): int
{ {

View File

@ -2,165 +2,7 @@
namespace Kilo; namespace Kilo;
use ReflectionClass;
trait MagicProperties {
abstract public function __get(string $name);
public function __set(string $name, $value)
{
if (property_exists($this, $name))
{
$this->$name = $value;
}
}
public function __isset(string $name): bool
{
return isset($this->$name);
}
}
class Key {
public const ARROW_DOWN = 'ARROW_DOWN';
public const ARROW_LEFT = 'ARROW_LEFT';
public const ARROW_RIGHT = 'ARROW_RIGHT';
public const ARROW_UP = 'ARROW_UP';
public const BACKSPACE = 'BACKSPACE';
public const DEL_KEY = 'DELETE';
public const END_KEY = 'END';
public const ENTER = 'ENTER';
public const ESCAPE = 'ESCAPE';
public const HOME_KEY = 'HOME';
public const PAGE_DOWN = 'PAGE_DOWN';
public const PAGE_UP = 'PAGE_UP';
public static function getConstList(): array
{
return (new ReflectionClass(static::class))->getConstants();
}
}
class Highlight {
public const NORMAL = 0;
public const NUMBER = 1;
public const MATCH = 2;
}
function syntax_to_color(int $hl): int
{
switch ($hl)
{
case Highlight::NUMBER:
return 31; // Foreground Red
case Highlight::MATCH:
return 34; // Foreground Blue
default:
return 37; // Foreground White
}
}
/**
* @property-read int size
* @property-read int rsize
*/
class Row {
use MagicProperties;
public string $chars = '';
public string $render = '';
public array $hl = [];
public static function new(string $chars): self
{
return new self($chars);
}
private function __construct($chars)
{
$this->chars = $chars;
}
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";
}
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;
$i = 0;
while ($i < $this->rsize)
{
$char = $this->render[$i];
$prevHl = ($i > 0) ? $this->hl[$i - 1] : Highlight::NORMAL;
// 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;
}
$prevSep = is_separator($char);
$i++;
}
}
}
/** /**
* @property-read int numRows * @property-read int numRows

9
src/Highlight.php Normal file
View File

@ -0,0 +1,9 @@
<?php declare(strict_types=1);
namespace Kilo;
class Highlight {
public const NORMAL = 0;
public const NUMBER = 1;
public const MATCH = 2;
}

25
src/Key.php Normal file
View File

@ -0,0 +1,25 @@
<?php declare(strict_types=1);
namespace Kilo;
use ReflectionClass;
class Key {
public const ARROW_DOWN = 'ARROW_DOWN';
public const ARROW_LEFT = 'ARROW_LEFT';
public const ARROW_RIGHT = 'ARROW_RIGHT';
public const ARROW_UP = 'ARROW_UP';
public const BACKSPACE = 'BACKSPACE';
public const DEL_KEY = 'DELETE';
public const END_KEY = 'END';
public const ENTER = 'ENTER';
public const ESCAPE = 'ESCAPE';
public const HOME_KEY = 'HOME';
public const PAGE_DOWN = 'PAGE_DOWN';
public const PAGE_UP = 'PAGE_UP';
public static function getConstList(): array
{
return (new ReflectionClass(static::class))->getConstants();
}
}

20
src/MagicProperties.php Normal file
View File

@ -0,0 +1,20 @@
<?php declare(strict_types=1);
namespace Kilo;
trait MagicProperties {
abstract public function __get(string $name);
public function __set(string $name, $value)
{
if (property_exists($this, $name))
{
$this->$name = $value;
}
}
public function __isset(string $name): bool
{
return isset($this->$name);
}
}

103
src/Row.php Normal file
View File

@ -0,0 +1,103 @@
<?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 = '';
public array $hl = [];
public static function new(string $chars): self
{
return new self($chars);
}
private function __construct($chars)
{
$this->chars = $chars;
}
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";
}
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;
$i = 0;
while ($i < $this->rsize)
{
$char = $this->render[$i];
$prevHl = ($i > 0) ? $this->hl[$i - 1] : Highlight::NORMAL;
// 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;
}
$prevSep = is_separator($char);
$i++;
}
}
}

View File

@ -275,3 +275,18 @@ function array_replace_range(array &$array, int $offset, int $length, $value):vo
$array[$i] = $value; $array[$i] = $value;
} }
} }
function syntax_to_color(int $hl): int
{
switch ($hl)
{
case Highlight::NUMBER:
return 31; // Foreground Red
case Highlight::MATCH:
return 34; // Foreground Blue
default:
return 37; // Foreground White
}
}