Up to step 71 in tutorial
This commit is contained in:
parent
5e6e6e7c7d
commit
9184a9b90f
12
kilo
12
kilo
@ -7,14 +7,20 @@ require_once __DIR__ . '/src/constants.php';
|
||||
require_once __DIR__ . '/src/functions.php';
|
||||
require_once __DIR__ . '/src/Editor.php';
|
||||
|
||||
function main(): int
|
||||
function main(int $argc, array $argv): int
|
||||
{
|
||||
global $ffi;
|
||||
|
||||
enableRawMode();
|
||||
|
||||
// ob_start();
|
||||
$editor = new Editor($ffi);
|
||||
$editor = Editor::new($ffi);
|
||||
|
||||
if ($argc >= 2)
|
||||
{
|
||||
$editor->open($argv[1]);
|
||||
}
|
||||
|
||||
|
||||
// Input Loop
|
||||
while (true)
|
||||
@ -28,4 +34,4 @@ function main(): int
|
||||
}
|
||||
|
||||
//! Init
|
||||
main();
|
||||
main($argc, $argv);
|
||||
|
117
src/Editor.php
117
src/Editor.php
@ -16,16 +16,42 @@ class Key {
|
||||
public const PAGE_DOWN = 'PAGE_DOWN';
|
||||
}
|
||||
|
||||
class Row {
|
||||
public string $chars;
|
||||
|
||||
public static function new(string $chars): self
|
||||
{
|
||||
return new self($chars);
|
||||
}
|
||||
|
||||
private function __construct($chars)
|
||||
{
|
||||
$this->chars = $chars;
|
||||
}
|
||||
}
|
||||
|
||||
class Editor {
|
||||
private FFI $ffi;
|
||||
|
||||
protected int $cursorx = 0;
|
||||
protected int $cursory = 0;
|
||||
protected int $rowoff = 0;
|
||||
protected int $coloff = 0;
|
||||
protected int $screenRows = 0;
|
||||
protected int $screenCols = 0;
|
||||
protected string $ab = '';
|
||||
|
||||
public function __construct($ffi)
|
||||
/**
|
||||
* Array of Row objects
|
||||
*/
|
||||
protected array $rows = [];
|
||||
|
||||
public static function new(FFI $ffi): Editor
|
||||
{
|
||||
return new self($ffi);
|
||||
}
|
||||
|
||||
private function __construct($ffi)
|
||||
{
|
||||
$this->ffi = $ffi;
|
||||
|
||||
@ -135,15 +161,63 @@ class Editor {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// ! Row Operations
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
protected function appendRow(string $s): void
|
||||
{
|
||||
$this->rows[] = Row::new($s);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// ! File I/O
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public function open(string $filename): void
|
||||
{
|
||||
$baseFile = basename($filename);
|
||||
$basePath = str_replace($baseFile, '', $filename);
|
||||
$path = (is_dir($basePath)) ? $basePath : getcwd();
|
||||
|
||||
$fullname = $path . '/' . $baseFile;
|
||||
|
||||
|
||||
$handle = fopen($fullname, 'rb');
|
||||
|
||||
while (($line = fgets($handle)) !== FALSE)
|
||||
{
|
||||
$this->appendRow($line);
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// ! Output
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
protected function scroll(): void
|
||||
{
|
||||
if ($this->cursory < $this->rowoff)
|
||||
{
|
||||
$this->rowoff = $this->cursory;
|
||||
}
|
||||
|
||||
if ($this->cursory >= $this->rowoff + $this->screenRows)
|
||||
{
|
||||
$this->rowoff = $this->cursory - $this->screenRows + 1;
|
||||
}
|
||||
}
|
||||
|
||||
protected function drawRows(): void
|
||||
{
|
||||
for ($y = 0; $y < $this->screenRows; $y++)
|
||||
{
|
||||
if ($y === ($this->screenRows / 3))
|
||||
$filerow = $y + $this->rowoff;
|
||||
if ($filerow >= count($this->rows))
|
||||
{
|
||||
if (count($this->rows) === 0 && $y === $this->screenRows / 3)
|
||||
{
|
||||
$welcome = sprintf('PHP Kilo editor -- version %s', KILO_VERSION);
|
||||
$welcomelen = strlen($welcome);
|
||||
@ -164,12 +238,26 @@ class Editor {
|
||||
}
|
||||
|
||||
$this->ab .= substr($welcome, 0, $welcomelen);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->ab .= '~';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$len = strlen($this->rows[$filerow]->chars) - $this->coloff;
|
||||
if ($len < 0)
|
||||
{
|
||||
$len = 0;
|
||||
}
|
||||
if ($len > $this->screenCols)
|
||||
{
|
||||
$len = $this->screenCols;
|
||||
}
|
||||
|
||||
$this->ab .= substr($this->rows[$filerow]->chars, $this->coloff, $len);
|
||||
}
|
||||
|
||||
$this->ab .= "\x1b[K"; // Clear the current line
|
||||
if ($y < $this->screenRows - 1)
|
||||
@ -181,6 +269,8 @@ class Editor {
|
||||
|
||||
public function refreshScreen(): void
|
||||
{
|
||||
$this->scroll();
|
||||
|
||||
$this->ab = '';
|
||||
|
||||
$this->ab .= "\x1b[?25l"; // Hide the cursor
|
||||
@ -189,7 +279,7 @@ class Editor {
|
||||
$this->drawRows();
|
||||
|
||||
// Specify the current cursor position
|
||||
$this->ab .= sprintf("\x1b[%d;%dH", $this->cursory + 1, $this->cursorx + 1);
|
||||
$this->ab .= sprintf("\x1b[%d;%dH", ($this->cursory - $this->rowoff) + 1, $this->cursorx + 1);
|
||||
|
||||
$this->ab .= "\x1b[?25h"; // Show the cursor
|
||||
|
||||
@ -226,7 +316,7 @@ class Editor {
|
||||
break;
|
||||
|
||||
case Key::ARROW_DOWN:
|
||||
if ($this->cursory !== $this->screenRows - 1)
|
||||
if ($this->cursory < count($this->rows))
|
||||
{
|
||||
$this->cursory++;
|
||||
}
|
||||
@ -255,13 +345,7 @@ class Editor {
|
||||
|
||||
case Key::PAGE_UP:
|
||||
case Key::PAGE_DOWN:
|
||||
{
|
||||
$times = $this->screenRows;
|
||||
while ($times--)
|
||||
{
|
||||
$this->moveCursor($c === Key::PAGE_UP ? Key::ARROW_UP : Key::ARROW_DOWN);
|
||||
}
|
||||
}
|
||||
$this->pageUpOrDown($c);
|
||||
break;
|
||||
|
||||
case Key::ARROW_UP:
|
||||
@ -274,4 +358,13 @@ class Editor {
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
private function pageUpOrDown(string $c):void
|
||||
{
|
||||
$times = $this->screenRows;
|
||||
while ($times--)
|
||||
{
|
||||
$this->moveCursor($c === Key::PAGE_UP ? Key::ARROW_UP : Key::ARROW_DOWN);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user