From 9184a9b90f1c1baf6da2a824c22b5e2c1e61799b Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Tue, 15 Oct 2019 13:23:25 -0400 Subject: [PATCH] Up to step 71 in tutorial --- kilo | 12 +++- src/Editor.php | 147 ++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 129 insertions(+), 30 deletions(-) diff --git a/kilo b/kilo index 8b7d751..2f3cd90 100755 --- a/kilo +++ b/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); diff --git a/src/Editor.php b/src/Editor.php index cac2abc..5e7eb9b 100644 --- a/src/Editor.php +++ b/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,40 +161,102 @@ 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)) { - $welcome = sprintf('PHP Kilo editor -- version %s', KILO_VERSION); - $welcomelen = strlen($welcome); - if ($welcomelen > $this->screenCols) + if (count($this->rows) === 0 && $y === $this->screenRows / 3) { - $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; - if ($padding) + $padding = ($this->screenCols - $welcomelen) / 2; + if ($padding) + { + $this->ab .= '~'; + $padding--; + } + while ($padding--) + { + $this->ab .= ' '; + } + + $this->ab .= substr($welcome, 0, $welcomelen); + } + else { $this->ab .= '~'; - $padding--; } - while ($padding--) - { - $this->ab .= ' '; - } - - $this->ab .= substr($welcome, 0, $welcomelen); - } 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 @@ -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); + } + } } \ No newline at end of file