Up to step 71 in tutorial

This commit is contained in:
Timothy Warren 2019-10-15 13:23:25 -04:00
parent 5e6e6e7c7d
commit 9184a9b90f
2 changed files with 129 additions and 30 deletions

12
kilo
View File

@ -7,14 +7,20 @@ require_once __DIR__ . '/src/constants.php';
require_once __DIR__ . '/src/functions.php'; require_once __DIR__ . '/src/functions.php';
require_once __DIR__ . '/src/Editor.php'; require_once __DIR__ . '/src/Editor.php';
function main(): int function main(int $argc, array $argv): int
{ {
global $ffi; global $ffi;
enableRawMode(); enableRawMode();
// ob_start(); // ob_start();
$editor = new Editor($ffi); $editor = Editor::new($ffi);
if ($argc >= 2)
{
$editor->open($argv[1]);
}
// Input Loop // Input Loop
while (true) while (true)
@ -28,4 +34,4 @@ function main(): int
} }
//! Init //! Init
main(); main($argc, $argv);

View File

@ -16,16 +16,42 @@ class Key {
public const PAGE_DOWN = 'PAGE_DOWN'; 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 { class Editor {
private FFI $ffi; private FFI $ffi;
protected int $cursorx = 0; protected int $cursorx = 0;
protected int $cursory = 0; protected int $cursory = 0;
protected int $rowoff = 0;
protected int $coloff = 0;
protected int $screenRows = 0; protected int $screenRows = 0;
protected int $screenCols = 0; protected int $screenCols = 0;
protected string $ab = ''; 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; $this->ffi = $ffi;
@ -135,40 +161,102 @@ class Editor {
return true; 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 // ! 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 protected function drawRows(): void
{ {
for ($y = 0; $y < $this->screenRows; $y++) for ($y = 0; $y < $this->screenRows; $y++)
{ {
if ($y === ($this->screenRows / 3)) $filerow = $y + $this->rowoff;
if ($filerow >= count($this->rows))
{ {
$welcome = sprintf('PHP Kilo editor -- version %s', KILO_VERSION); if (count($this->rows) === 0 && $y === $this->screenRows / 3)
$welcomelen = strlen($welcome);
if ($welcomelen > $this->screenCols)
{ {
$welcomelen = $this->screenCols; $welcome = sprintf('PHP Kilo editor -- version %s', KILO_VERSION);
} $welcomelen = strlen($welcome);
if ($welcomelen > $this->screenCols)
{
$welcomelen = $this->screenCols;
}
$padding = ($this->screenCols - $welcomelen) / 2; $padding = ($this->screenCols - $welcomelen) / 2;
if ($padding) if ($padding)
{
$this->ab .= '~';
$padding--;
}
while ($padding--)
{
$this->ab .= ' ';
}
$this->ab .= substr($welcome, 0, $welcomelen);
}
else
{ {
$this->ab .= '~'; $this->ab .= '~';
$padding--;
} }
while ($padding--)
{
$this->ab .= ' ';
}
$this->ab .= substr($welcome, 0, $welcomelen);
} }
else else
{ {
$this->ab .= '~'; $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 $this->ab .= "\x1b[K"; // Clear the current line
@ -181,6 +269,8 @@ class Editor {
public function refreshScreen(): void public function refreshScreen(): void
{ {
$this->scroll();
$this->ab = ''; $this->ab = '';
$this->ab .= "\x1b[?25l"; // Hide the cursor $this->ab .= "\x1b[?25l"; // Hide the cursor
@ -189,7 +279,7 @@ class Editor {
$this->drawRows(); $this->drawRows();
// Specify the current cursor position // 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 $this->ab .= "\x1b[?25h"; // Show the cursor
@ -226,7 +316,7 @@ class Editor {
break; break;
case Key::ARROW_DOWN: case Key::ARROW_DOWN:
if ($this->cursory !== $this->screenRows - 1) if ($this->cursory < count($this->rows))
{ {
$this->cursory++; $this->cursory++;
} }
@ -255,13 +345,7 @@ class Editor {
case Key::PAGE_UP: case Key::PAGE_UP:
case Key::PAGE_DOWN: case Key::PAGE_DOWN:
{ $this->pageUpOrDown($c);
$times = $this->screenRows;
while ($times--)
{
$this->moveCursor($c === Key::PAGE_UP ? Key::ARROW_UP : Key::ARROW_DOWN);
}
}
break; break;
case Key::ARROW_UP: case Key::ARROW_UP:
@ -274,4 +358,13 @@ class Editor {
return $c; 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);
}
}
} }