Complete step 164

This commit is contained in:
Timothy Warren 2019-10-25 10:28:15 -04:00
parent 79d9a6def3
commit 5566441dc3
4 changed files with 132 additions and 60 deletions

1
kilo
View File

@ -12,6 +12,7 @@ define('KILO_QUIT_TIMES', 3);
// Set up autoloading // Set up autoloading
require_once __DIR__ . '/src/functions.php'; require_once __DIR__ . '/src/functions.php';
require_once __DIR__ . '/src/hldb.php';
spl_autoload_register(static function ($class) { spl_autoload_register(static function ($class) {
$parts = explode('\\', $class); $parts = explode('\\', $class);
$file = __DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $parts[1] . '.php'; $file = __DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $parts[1] . '.php';

View File

@ -23,11 +23,13 @@ class Editor {
*/ */
protected array $rows = []; protected array $rows = [];
protected int $dirty = 0; public int $dirty = 0;
protected string $filename = ''; protected string $filename = '';
protected string $statusMsg = ''; protected string $statusMsg = '';
protected int $statusMsgTime; protected int $statusMsgTime;
public ?Syntax $syntax;
public static function new(): Editor public static function new(): Editor
{ {
return new self(); return new self();
@ -97,6 +99,42 @@ class Editor {
} }
} }
protected function selectSyntaxHighlight(): void
{
$this->syntax = NULL;
if (empty($this->filename))
{
return;
}
// In PHP, `strchr` and `strstr` are the same function
$ext = (string)strstr($this->filename, '.');
foreach (get_hldb() as $syntax)
{
$i = 0;
while ($syntax->filematch[$i])
{
$is_ext = ($syntax->filematch[$i][0] === '.');
if (
($is_ext && ( ! strcmp($ext, $syntax->filematch[$i]))) ||
(( ! $is_ext) && strpos($this->filename, $syntax->filematch{$i}) !== FALSE)
) {
$this->syntax = $syntax;
for ($i = 0; $i < $this->numRows; $i++)
{
$this->rows[$i]->update();
}
return;
}
$i++;
}
}
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// ! Row Operations // ! Row Operations
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -143,7 +181,7 @@ class Editor {
return; return;
} }
$row = Row::new($s); $row = Row::new($this, $s);
if ($at === $this->numRows) if ($at === $this->numRows)
{ {
@ -179,38 +217,6 @@ class Editor {
$this->dirty++; $this->dirty++;
} }
protected function rowInsertChar(Row $row, int $at, string $c): void
{
if ($at < 0 || $at > $row->size)
{
$at = $row->size;
}
// Safely insert into arbitrary position in the existing string
$row->chars = substr($row->chars, 0, $at) . $c . substr($row->chars, $at);
$row->update();
$this->dirty++;
}
protected function rowAppendString(Row $row, string $s): void
{
$row->chars .= $s;
$row->update();
$this->dirty++;
}
protected function rowDeleteChar(Row $row, int $at): void
{
if ($at < 0 || $at >= $row->size)
{
return;
}
$row->chars = substr_replace($row->chars, '', $at, 1);
$row->update();
$this->dirty++;
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// ! Editor Operations // ! Editor Operations
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -221,7 +227,7 @@ class Editor {
{ {
$this->insertRow($this->numRows, ''); $this->insertRow($this->numRows, '');
} }
$this->rowInsertChar($this->rows[$this->cursorY], $this->cursorX, $c); $this->rows[$this->cursorY]->insertChar($this->cursorX, $c);
$this->cursorX++; $this->cursorX++;
} }
@ -257,13 +263,13 @@ class Editor {
$row = $this->rows[$this->cursorY]; $row = $this->rows[$this->cursorY];
if ($this->cursorX > 0) if ($this->cursorX > 0)
{ {
$this->rowDeleteChar($row, $this->cursorX - 1); $row->deleteChar($this->cursorX - 1);
$this->cursorX--; $this->cursorX--;
} }
else else
{ {
$this->cursorX = $this->rows[$this->cursorY - 1]->size; $this->cursorX = $this->rows[$this->cursorY - 1]->size;
$this->rowAppendString($this->rows[$this->cursorY -1], $row->chars); $this->rows[$this->cursorY -1]->appendString($row->chars);
$this->deleteRow($this->cursorY); $this->deleteRow($this->cursorY);
$this->cursorY--; $this->cursorY--;
} }
@ -289,12 +295,7 @@ class Editor {
// Copy filename for display // Copy filename for display
$this->filename = $filename; $this->filename = $filename;
// Determine the full path to the file $this->selectSyntaxHighlight();
/* $baseFile = basename($filename);
$basePath = str_replace($baseFile, '', $filename);
$path = (is_dir($basePath)) ? $basePath : getcwd();
$fullname = $path . '/' . $baseFile; */
// #TODO gracefully handle issues with loading a file // #TODO gracefully handle issues with loading a file
$handle = fopen($filename, 'rb'); $handle = fopen($filename, 'rb');
@ -302,7 +303,7 @@ class Editor {
{ {
write_stdout("\x1b[2J"); // Clear the screen write_stdout("\x1b[2J"); // Clear the screen
write_stdout("\x1b[H"); // Reposition cursor to top-left write_stdout("\x1b[H"); // Reposition cursor to top-left
disableRawMode(); disable_raw_mode();
print_r(error_get_last()); print_r(error_get_last());
die(); die();
} }
@ -330,6 +331,7 @@ class Editor {
} }
$this->filename = $newFilename; $this->filename = $newFilename;
$this->selectSyntaxHighlight();
} }
$contents = $this->rowsToString(); $contents = $this->rowsToString();
@ -565,9 +567,10 @@ class Editor {
$this->ab .= "\x1b[7m"; $this->ab .= "\x1b[7m";
$statusFilename = $this->filename !== '' ? $this->filename : '[No Name]'; $statusFilename = $this->filename !== '' ? $this->filename : '[No Name]';
$syntaxType = ($this->syntax !== NULL) ? $this->syntax->filetype : 'no ft';
$isDirty = ($this->dirty > 0) ? '(modified)' : ''; $isDirty = ($this->dirty > 0) ? '(modified)' : '';
$status = sprintf('%.20s - %d lines %s', $statusFilename, $this->numRows, $isDirty); $status = sprintf('%.20s - %d lines %s', $statusFilename, $this->numRows, $isDirty);
$rstatus = sprintf('%d/%d', $this->cursorY + 1, $this->numRows); $rstatus = sprintf('%s | %d/%d', $syntaxType, $this->cursorY + 1, $this->numRows);
$len = strlen($status); $len = strlen($status);
$rlen = strlen($rstatus); $rlen = strlen($rstatus);
if ($len > $this->screenCols) if ($len > $this->screenCols)

View File

@ -12,17 +12,21 @@ class Row {
public string $chars = ''; public string $chars = '';
public string $render = ''; public string $render = '';
// This feels dirty...
private Editor $parent;
public array $hl = []; public array $hl = [];
public static function new(string $chars): self public static function new(Editor $parent, string $chars): self
{ {
return new self($chars); $self = new self();
$self->chars = $chars;
$self->parent = $parent;
return $self;
} }
private function __construct($chars) private function __construct() {}
{
$this->chars = $chars;
}
public function __get(string $name) public function __get(string $name)
{ {
@ -44,6 +48,41 @@ class Row {
return $this->chars . "\n"; return $this->chars . "\n";
} }
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++;
}
public function update(): void public function update(): void
{ {
$idx = 0; $idx = 0;
@ -84,16 +123,24 @@ class Row {
$char = $this->render[$i]; $char = $this->render[$i];
$prevHl = ($i > 0) ? $this->hl[$i - 1] : Highlight::NORMAL; $prevHl = ($i > 0) ? $this->hl[$i - 1] : Highlight::NORMAL;
// Numbers, including decimal points if ($this->parent->syntax === NULL)
if (
($char === '.' && $prevHl === Highlight::NUMBER) ||
(($prevSep || $prevHl === Highlight::NUMBER) && is_digit($char))
)
{ {
$this->hl[$i] = Highlight::NUMBER; return;
$i++; }
$prevSep = FALSE;
continue; if ($this->parent->syntax->flags & Syntax::HIGHLIGHT_NUMBERS)
{
// 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); $prevSep = is_separator($char);

21
src/hldb.php Normal file
View File

@ -0,0 +1,21 @@
<?php declare(strict_types=1);
namespace Kilo;
function get_hldb(): array
{
static $db = [];
if (count($db) === 0)
{
$db = [
Syntax::new(
'c',
['.c', '.h', '.cpp'],
Syntax::HIGHLIGHT_NUMBERS,
),
];
}
return $db;
}