Move some logic to Document class
This commit is contained in:
parent
633094ea9f
commit
7d381d10e9
130
src/Document.php
130
src/Document.php
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Aviat\Kilo;
|
namespace Aviat\Kilo;
|
||||||
|
|
||||||
|
use Aviat\Kilo\Tokens\PHP8;
|
||||||
use Aviat\Kilo\Type\Point;
|
use Aviat\Kilo\Type\Point;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -10,16 +11,18 @@ use Aviat\Kilo\Type\Point;
|
|||||||
* @property-read int $numRows
|
* @property-read int $numRows
|
||||||
*/
|
*/
|
||||||
class Document {
|
class Document {
|
||||||
public ?Syntax $syntax = NULL;
|
public FileType $fileType;
|
||||||
|
|
||||||
// Tokens for highlighting PHP
|
// Tokens for highlighting PHP
|
||||||
public array $tokens = [];
|
public array $tokens = [];
|
||||||
|
|
||||||
private function __construct(
|
private function __construct(
|
||||||
public array $rows = [],
|
public array $rows = [],
|
||||||
public ?string $filename = NULL,
|
public string $filename = '',
|
||||||
private bool $dirty = FALSE,
|
public bool $dirty = FALSE,
|
||||||
) {}
|
) {
|
||||||
|
$this->fileType = FileType::from($this->filename);
|
||||||
|
}
|
||||||
|
|
||||||
public function __get(string $name): ?int
|
public function __get(string $name): ?int
|
||||||
{
|
{
|
||||||
@ -31,21 +34,53 @@ class Document {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function new(): self
|
public static function default(): self
|
||||||
{
|
{
|
||||||
return new self();
|
return new self();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function open(?string $filename = NULL): self
|
protected function rowsToString(): string
|
||||||
{
|
{
|
||||||
// @TODO move logic from Editor
|
$lines = array_map(fn (Row $row) => (string)$row, $this->rows);
|
||||||
return new self(filename: $filename);
|
|
||||||
|
return implode('', $lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save(): bool
|
public static function open(string $filename): ?self
|
||||||
{
|
{
|
||||||
// @TODO move logic
|
$handle = fopen($filename, 'rb');
|
||||||
return false;
|
if ($handle === FALSE)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self = new self(filename: $filename);
|
||||||
|
|
||||||
|
while (($line = fgets($handle)) !== FALSE)
|
||||||
|
{
|
||||||
|
// Remove line endings when reading the file
|
||||||
|
$self->insertRow($self->numRows, rtrim($line), FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($handle);
|
||||||
|
|
||||||
|
$self->selectSyntaxHighlight();
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save(): int|false
|
||||||
|
{
|
||||||
|
$contents = $this->rowsToString();
|
||||||
|
|
||||||
|
$res = file_put_contents($this->filename, $contents);
|
||||||
|
|
||||||
|
if ($res === strlen($contents))
|
||||||
|
{
|
||||||
|
$this->dirty = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function insertChar(Point $at, string $c): void
|
public function insertChar(Point $at, string $c): void
|
||||||
@ -53,6 +88,47 @@ class Document {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function insertRow(int $at, string $s, bool $updateSyntax = TRUE): void
|
||||||
|
{
|
||||||
|
if ($at > $this->numRows)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$row = Row::new($this, $s, $at);
|
||||||
|
|
||||||
|
if ($at === $this->numRows)
|
||||||
|
{
|
||||||
|
$this->rows[] = $row;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->rows = [
|
||||||
|
...array_slice($this->rows, 0, $at),
|
||||||
|
$row,
|
||||||
|
...array_slice($this->rows, $at),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Update indexes of each row so that correct highlighting is done
|
||||||
|
for ($idx = $at; $idx < $this->numRows; $idx++)
|
||||||
|
{
|
||||||
|
$this->rows[$idx]->idx = $idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($this->rows);
|
||||||
|
|
||||||
|
$this->rows[$at]->update();
|
||||||
|
|
||||||
|
$this->dirty = true;
|
||||||
|
|
||||||
|
// Re-tokenize the file
|
||||||
|
if ($updateSyntax)
|
||||||
|
{
|
||||||
|
$this->refreshPHPSyntax();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function isDirty(): bool
|
public function isDirty(): bool
|
||||||
{
|
{
|
||||||
return $this->dirty;
|
return $this->dirty;
|
||||||
@ -67,4 +143,36 @@ class Document {
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function selectSyntaxHighlight(): void
|
||||||
|
{
|
||||||
|
if (empty($this->filename))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->fileType->name === 'PHP')
|
||||||
|
{
|
||||||
|
$this->tokens = PHP8::getFileTokens($this->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->refreshSyntax();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function refreshSyntax(): void
|
||||||
|
{
|
||||||
|
// Update the syntax highlighting for all the rows of the file
|
||||||
|
array_walk($this->rows, static fn (Row $row) => $row->update());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function refreshPHPSyntax(): void
|
||||||
|
{
|
||||||
|
if ($this->fileType->name !== 'PHP')
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->tokens = PHP8::getTokens($this->rowsToString());
|
||||||
|
$this->refreshSyntax();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ use Aviat\Kilo\Type\{Point, StatusMessage};
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* // Don't highlight this!
|
* // Don't highlight this!
|
||||||
* @property-read int $numRows
|
|
||||||
*/
|
*/
|
||||||
class Editor {
|
class Editor {
|
||||||
use Traits\MagicProperties;
|
use Traits\MagicProperties;
|
||||||
|
76
src/FileType.php
Normal file
76
src/FileType.php
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Aviat\Kilo;
|
||||||
|
|
||||||
|
class FileType {
|
||||||
|
|
||||||
|
public static function from(?string $filename): self
|
||||||
|
{
|
||||||
|
$syntax = self::getSyntaxFromFilename((string)$filename);
|
||||||
|
|
||||||
|
return new self($syntax->filetype, $syntax);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getSyntaxFromFilename(string $filename): Syntax
|
||||||
|
{
|
||||||
|
$ext = (string)strstr(basename($filename), '.');
|
||||||
|
return match ($ext) {
|
||||||
|
'.php', 'kilo' => Syntax::new(
|
||||||
|
'PHP',
|
||||||
|
['.php', 'kilo'],
|
||||||
|
),
|
||||||
|
'.c', '.h', '.cpp', '.cxx', '.cc', '.hpp' => Syntax::new(
|
||||||
|
'C',
|
||||||
|
['.c', '.h', '.cpp'],
|
||||||
|
[
|
||||||
|
'continue', 'typedef', 'switch', 'return', 'static', 'while', 'break', 'struct',
|
||||||
|
'union', 'class', 'else', 'enum', 'for', 'case', 'if',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#include', 'unsigned', '#define', '#ifndef', 'double', 'signed', '#endif',
|
||||||
|
'#ifdef', 'float', '#error', '#undef', 'long', 'char', 'int', 'void', '#if',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
'.css', '.less', '.sass', '.scss' => Syntax::new(
|
||||||
|
'CSS',
|
||||||
|
['.css', '.less', '.sass', 'scss'],
|
||||||
|
slcs: '',
|
||||||
|
),
|
||||||
|
'.js', '.jsx', '.ts', '.tsx', '.jsm', '.mjs', '.es' => Syntax::new(
|
||||||
|
'JavaScript',
|
||||||
|
['.js', '.jsx', '.ts', '.tsx', '.jsm', '.mjs', '.es'],
|
||||||
|
[
|
||||||
|
'instanceof', 'continue', 'debugger', 'function', 'default', 'extends',
|
||||||
|
'finally', 'delete', 'export', 'import', 'return', 'switch', 'typeof',
|
||||||
|
'break', 'catch', 'class', 'const', 'super', 'throw', 'while', 'yield',
|
||||||
|
'case', 'else', 'this', 'void', 'with', 'from', 'for', 'new', 'try',
|
||||||
|
'var', 'do', 'if', 'in', 'as',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'=>', 'Number', 'String', 'Object', 'Math', 'JSON', 'Boolean',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
'.rs' => Syntax::new(
|
||||||
|
'Rust',
|
||||||
|
['.rs'],
|
||||||
|
[
|
||||||
|
'continue', 'return', 'static', 'struct', 'unsafe', 'break', 'const', 'crate',
|
||||||
|
'extern', 'match', 'super', 'trait', 'where', 'else', 'enum', 'false', 'impl',
|
||||||
|
'loop', 'move', 'self', 'type', 'while', 'for', 'let', 'mod', 'pub', 'ref', 'true',
|
||||||
|
'use', 'mut', 'as', 'fn', 'if', 'in',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'DoubleEndedIterator', 'ExactSizeIterator', 'IntoIterator', 'PartialOrd', 'PartialEq',
|
||||||
|
'Iterator', 'ToString', 'Default', 'ToOwned', 'Extend', 'FnOnce', 'Option', 'String',
|
||||||
|
'AsMut', 'AsRef', 'Clone', 'Debug', 'FnMut', 'Sized', 'Unpin', 'array', 'isize',
|
||||||
|
'usize', '&str', 'Copy', 'Drop', 'From', 'Into', 'None', 'Self', 'Send', 'Some',
|
||||||
|
'Sync', 'bool', 'char', 'i128', 'u128', 'Box', 'Err', 'Ord', 'Vec', 'dyn', 'f32',
|
||||||
|
'f64', 'i16', 'i32', 'i64', 'str', 'u16', 'u32', 'u64', 'Eq', 'Fn', 'Ok', 'i8', 'u8',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
default => Syntax::default(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private function __construct(public string $name, public Syntax $syntax) {}
|
||||||
|
}
|
@ -17,12 +17,17 @@ class Syntax {
|
|||||||
string $slcs = '//',
|
string $slcs = '//',
|
||||||
string $mcs = '/*',
|
string $mcs = '/*',
|
||||||
string $mce = '*/',
|
string $mce = '*/',
|
||||||
int $flags = 0,
|
int $flags = self::HIGHLIGHT_NUMBERS | self::HIGHLIGHT_STRINGS,
|
||||||
): self
|
): self
|
||||||
{
|
{
|
||||||
return new self($name, $extList, $keywords1, $keywords2, $slcs, $mcs, $mce, $flags);
|
return new self($name, $extList, $keywords1, $keywords2, $slcs, $mcs, $mce, $flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function default(): self
|
||||||
|
{
|
||||||
|
return self::new('No filetype', slcs: '', mcs: '', mce: '', flags: 0);
|
||||||
|
}
|
||||||
|
|
||||||
private function __construct(
|
private function __construct(
|
||||||
/** The name of the programming language */
|
/** The name of the programming language */
|
||||||
public string $filetype,
|
public string $filetype,
|
||||||
|
Loading…
Reference in New Issue
Block a user