Some refactoring
timw4mail/php-kilo/pipeline/head This commit looks good Details

This commit is contained in:
Timothy Warren 2021-03-09 17:22:49 -05:00
parent 5329378b93
commit 99685f3fcb
7 changed files with 2552 additions and 2200 deletions

11
kilo
View File

@ -6,7 +6,7 @@ namespace Aviat\Kilo;
require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/vendor/autoload.php';
// Log notices/errors/warnings to file // Log notices/errors/warnings to file
set_exception_handler(static function (\Throwable $e) { set_exception_handler(static function (mixed $e) {
$msg = print_r([ $msg = print_r([
'code' => $e->getCode(), 'code' => $e->getCode(),
'message' => $e->getMessage(), 'message' => $e->getMessage(),
@ -31,7 +31,14 @@ return (static function (int $argc, array $argv): int {
} }
// Input Loop // Input Loop
do { $editor->refreshScreen();} while ($editor->processKeypress() !== NULL); while (true)
{
$editor->refreshScreen();
if ($editor->processKeypress() === NULL)
{
break;
}
}
return 0; return 0;
})($argc, $argv); })($argc, $argv);

View File

@ -53,7 +53,7 @@ class ANSI {
*/ */
public static function color(int $color): string public static function color(int $color): string
{ {
return self::seq('%dm', $color); return self::escapeSequence('%dm', $color);
} }
/** /**
@ -66,7 +66,7 @@ class ANSI {
*/ */
public static function rgbColor(int $r, int $g, int $b): string public static function rgbColor(int $r, int $g, int $b): string
{ {
return self::seq('38;2;%d;%d;%dm', $r, $g, $b); return self::escapeSequence('38;2;%d;%d;%dm', $r, $g, $b);
} }
/** /**
@ -80,7 +80,7 @@ class ANSI {
{ {
// The terminal has a 1-based coordinate system, // The terminal has a 1-based coordinate system,
// add one to each to allow 0-based coordinate system input // add one to each to allow 0-based coordinate system input
return self::seq('%d;%dH', $line + 1, $column + 1); return self::escapeSequence('%d;%dH', $line + 1, $column + 1);
} }
/** /**
@ -91,7 +91,7 @@ class ANSI {
*/ */
public static function scrollUp(int $lines): string public static function scrollUp(int $lines): string
{ {
return self::seq('%dS', $lines); return self::escapeSequence('%dS', $lines);
} }
/** /**
@ -102,7 +102,7 @@ class ANSI {
*/ */
public static function scrollDown(int $lines): string public static function scrollDown(int $lines): string
{ {
return self::seq('%dT', $lines); return self::escapeSequence('%dT', $lines);
} }
/** /**
@ -112,7 +112,7 @@ class ANSI {
* @param mixed ...$args * @param mixed ...$args
* @return string * @return string
*/ */
private static function seq(string $pattern, mixed ...$args): string private static function escapeSequence(string $pattern, mixed ...$args): string
{ {
return sprintf("\e[{$pattern}", ...$args); return sprintf("\e[{$pattern}", ...$args);
} }

View File

@ -18,14 +18,14 @@ class Editor {
private string $outputBuffer = ''; private string $outputBuffer = '';
/** /**
* @var Position The 0-based location of the cursor in the current viewport * @var Point The 0-based location of the cursor in the current viewport
*/ */
protected Position $cursor; protected Point $cursor;
/** /**
* @var Position The scroll offset of the file in the current viewport * @var Point The scroll offset of the file in the current viewport
*/ */
protected Position $offset; protected Point $offset;
/** /**
* @var int The rendered cursor position * @var int The rendered cursor position
@ -42,6 +42,11 @@ class Editor {
*/ */
protected int $screenCols = 0; protected int $screenCols = 0;
/**
* @var int The number of times to confirm you wish to quit
*/
protected int $quitTimes = KILO_QUIT_TIMES;
/** /**
* Array of Row objects * Array of Row objects
*/ */
@ -65,8 +70,8 @@ class Editor {
private function __construct() private function __construct()
{ {
$this->statusMsgTime = time(); $this->statusMsgTime = time();
$this->cursor = Position::new(); $this->cursor = Point::new();
$this->offset = Position::new(); $this->offset = Point::new();
[$this->screenRows, $this->screenCols] = Terminal::getWindowSize(); [$this->screenRows, $this->screenCols] = Terminal::getWindowSize();
@ -507,10 +512,8 @@ class Editor {
protected function find(): void protected function find(): void
{ {
$savedCx = $this->cursor->x; $savedCursor = Point::from($this->cursor);
$savedCy = $this->cursor->y; $savedOffset = Point::from($this->offset);
$savedColOff = $this->offset->x;
$savedRowOff = $this->offset->y;
$query = $this->prompt('Search: %s (Use ESC/Arrows/Enter)', [$this, 'findCallback']); $query = $this->prompt('Search: %s (Use ESC/Arrows/Enter)', [$this, 'findCallback']);
@ -518,10 +521,8 @@ class Editor {
// restore original cursor and scroll locations // restore original cursor and scroll locations
if ($query === '') if ($query === '')
{ {
$this->cursor->x = $savedCx; $this->cursor = Point::from($savedCursor);
$this->cursor->y = $savedCy; $this->offset = Point::from($savedOffset);
$this->offset->x = $savedColOff;
$this->offset->y = $savedRowOff;
} }
} }
@ -564,11 +565,12 @@ class Editor {
{ {
$filerow = $y + $this->offset->y; $filerow = $y + $this->offset->y;
$this->outputBuffer .= ANSI::CLEAR_LINE;
($filerow >= $this->numRows) ($filerow >= $this->numRows)
? $this->drawPlaceholderRow($y) ? $this->drawPlaceholderRow($y)
: $this->drawRow($filerow); : $this->drawRow($filerow);
$this->outputBuffer .= ANSI::CLEAR_LINE;
$this->outputBuffer .= "\r\n"; $this->outputBuffer .= "\r\n";
} }
} }
@ -851,7 +853,7 @@ class Editor {
case KeyType::END_KEY: case KeyType::END_KEY:
if ($y < $this->numRows) if ($y < $this->numRows)
{ {
$x = $this->rows[$y]->size - 1; $x = $this->rows[$y]->size;
} }
break; break;
@ -859,13 +861,13 @@ class Editor {
// Do nothing // Do nothing
} }
if ($x > $row->size) // Snap cursor to the end of a row when moving
// from a longer row to a shorter one
$row = $this->rows[$y];
$rowLen = ($row !== NULL) ? $row->size : 0;
if ($x > $rowLen)
{ {
$x = $row->size; $x = $rowLen;
}
if ($y > $this->screenRows)
{
$y = $this->screenRows;
} }
$this->cursor->x = $x; $this->cursor->x = $x;
@ -874,8 +876,6 @@ class Editor {
public function processKeypress(): ?string public function processKeypress(): ?string
{ {
static $quit_times = KILO_QUIT_TIMES;
$c = $this->readKey(); $c = $this->readKey();
if ($c === KeyCode::NULL || $c === KeyCode::EMPTY) if ($c === KeyCode::NULL || $c === KeyCode::EMPTY)
@ -885,21 +885,13 @@ class Editor {
switch ($c) switch ($c)
{ {
case KeyCode::CTRL('q'):
return $this->quitAttempt();
case KeyType::ENTER: case KeyType::ENTER:
$this->insertNewline(); $this->insertNewline();
break; break;
case KeyCode::CTRL('q'):
if ($this->dirty > 0 && $quit_times > 0)
{
$this->setStatusMessage('WARNING!!! File has unsaved changes.' .
'Press Ctrl-Q %d more times to quit.', $quit_times);
$quit_times--;
return '';
}
Terminal::clear();
return NULL;
case KeyCode::CTRL('s'): case KeyCode::CTRL('s'):
$this->save(); $this->save();
break; break;
@ -938,15 +930,32 @@ class Editor {
break; break;
} }
$quit_times = KILO_QUIT_TIMES; // Reset quit confirmation timer on different keypress
$this->quitTimes = KILO_QUIT_TIMES;
return $c; return $c;
} }
protected function quitAttempt(): ?string
{
if ($this->dirty > 0 && $this->quitTimes > 0)
{
$this->setStatusMessage(
'WARNING!!! File has unsaved changes. Press Ctrl-Q %d more times to quit.',
$this->quitTimes
);
$this->quitTimes--;
return KeyCode::CTRL('q');
}
Terminal::clear();
return NULL;
}
protected function refreshSyntax(): void protected function refreshSyntax(): void
{ {
// Update the syntax highlighting for all the rows of the file // Update the syntax highlighting for all the rows of the file
array_walk($this->rows, static fn (Row $row) => $row->updateSyntax()); array_walk($this->rows, static fn (Row $row) => $row->update());
} }
private function refreshPHPSyntax(): void private function refreshPHPSyntax(): void

33
src/Point.php Normal file
View File

@ -0,0 +1,33 @@
<?php declare(strict_types=1);
namespace Aviat\Kilo;
/**
* A representation of a 2d point
*/
final class Point {
private function __construct(public int $x, public int $y) {}
/**
* Create a new Point from coordinates
*
* @param int $x
* @param int $y
* @return Point
*/
public static function new(int $x = 0, int $y = 0): Point
{
return new Point($x, $y);
}
/**
* Create a new Point from another position
*
* @param Point $pos
* @return Point
*/
public static function from(Point $pos): Point
{
return Point::new($pos->x, $pos->y);
}
}

View File

@ -1,12 +0,0 @@
<?php declare(strict_types=1);
namespace Aviat\Kilo;
class Position {
private function __construct(public int $x, public int $y) {}
public static function new(int $x = 0, int $y = 0): self
{
return new Position($x, $y);
}
}

View File

@ -16,6 +16,10 @@ abstract class Foo implements Ifoo {
protected function doNothing(): void {} protected function doNothing(): void {}
} }
class Test {
public function __construct(public string $foo, public string $bar) {}
}
/** /**
* Docblock comment * Docblock comment
*/ */
@ -116,4 +120,4 @@ TEMPLATE;
<h1><?= $_SERVER['HTTP_HOST'] ?></h1> <h1><?= $_SERVER['HTTP_HOST'] ?></h1>
</body> </body>
</html> </html>
<?php exit(); ?> <?php exit(); ?>

File diff suppressed because it is too large Load Diff