Replace inline ANSI escapes with constants and static methods
Gitea - Tutorials/php-kilo/master There was a failure building this commit Details

This commit is contained in:
Timothy Warren 2019-12-04 10:54:15 -05:00
parent 7acf38da9c
commit fb5dd66bee
8 changed files with 6281 additions and 4062 deletions

97
src/ANSI.php Normal file
View File

@ -0,0 +1,97 @@
<?php declare(strict_types=1);
namespace Aviat\Kilo;
/**
* ANSI
*/
class ANSI {
// ------------------------------------------------------------------------
// General ANSI standard escape sequences
// ------------------------------------------------------------------------
/**
* Clear the terminal window
*/
public const CLEAR_SCREEN = "\e[2J";
/**
* Clear the terminal line
*/
public const CLEAR_LINE = "\e[K";
// ------------------------------------------------------------------------
// Text formatting escape sequences
// ------------------------------------------------------------------------
/**
* Removes text attributes, such as bold, underline, blink, inverted colors
*/
public const RESET_TEXT = "\e[0m";
public const BOLD_TEXT = "\e[1m";
public const UNDERLINE_TEXT = "\e[4m";
/**
* Move the cursor to position 0,0 which is the top left
*/
public const RESET_CURSOR = "\e[H";
// ------------------------------------------------------------------------
// VT-series escapes, not really ANSI standard
// ------------------------------------------------------------------------
public const HIDE_CURSOR = "\e[?25l";
public const SHOW_CURSOR = "\e[?25h";
/**
* Generate the ascii sequence for basic text color
*
* @param int $color
* @return string
*/
public static function color(int $color): string
{
return sprintf("\e[%dm", $color);
}
public static function rgbColor(int $r, int $g, int $b): string
{
return sprintf("\e[38;2;%d;%d;%bm", $r, $g, $b);
}
/**
* Move the cursor the specified position
*
* @param int $line
* @param int $column
* @return string
*/
public static function moveCursor(int $line, int $column): string
{
return sprintf("\e[%d;%dH", $line, $column);
}
/**
* Scroll the specified number of lines up
*
* @param int $lines
* @return string
*/
public static function scrollUp(int $lines): string
{
return sprintf("\e[%dS", $lines);
}
/**
* Scroll the specified number of lines down
*
* @param int $lines
* @return string
*/
public static function scrollDown(int $lines): string
{
return sprintf("\e[%dT", $lines);
}
}

View File

@ -3,6 +3,7 @@
namespace Aviat\Kilo;
use Aviat\Kilo\Enum\{
Color,
Key,
Highlight,
};
@ -111,7 +112,7 @@ class Editor {
case "\x1bOH":
case "\x1b[1~":
case "\x1b[7~":
case "\x1b[H":
case ANSI::RESET_CURSOR:
return Key::HOME_KEY;
case "\x1bOF":
@ -363,8 +364,8 @@ class Editor {
$handle = fopen($filename, 'rb');
if ($handle === FALSE)
{
write_stdout("\x1b[2J"); // Clear the screen
write_stdout("\x1b[H"); // Reposition cursor to top-left
write_stdout(ANSI::CLEAR_SCREEN);
write_stdout(ANSI::RESET_CURSOR); // Reposition cursor to top-left
Termios::disableRawMode();
print_r(error_get_last());
die();
@ -604,20 +605,20 @@ class Editor {
$sym = (ord($c[$i]) <= 26)
? chr(ord('@') + ord($c[$i]))
: '?';
$this->ab .= "\x1b[7m";
$this->ab .= ANSI::color(Color::INVERT);
$this->ab .= $sym;
$this->ab .= "\x1b[m";
$this->ab .= ANSI::RESET_TEXT;
if ($currentColor !== -1)
{
$this->ab .= sprintf("\x1b%dm", $currentColor);
$this->ab .= ANSI::color($currentColor);
}
}
else if ($hl[$i] === Highlight::NORMAL)
{
if ($currentColor !== -1)
{
$this->ab .= "\x1b[0m"; // Reset background color
$this->ab .= "\x1b[39m"; // Reset foreground color
$this->ab .= ANSI::RESET_TEXT;
$this->ab .= ANSI::color(Color::FG_WHITE);
$currentColor = -1;
}
$this->ab .= $c[$i];
@ -628,25 +629,25 @@ class Editor {
if ($color !== $currentColor)
{
$currentColor = $color;
$this->ab .= "\x1b[0m"; // Reset background color
$this->ab .= sprintf("\x1b[%dm", $color);
$this->ab .= ANSI::RESET_TEXT;
$this->ab .= ANSI::color($color);
}
$this->ab .= $c[$i];
}
}
$this->ab .= "\x1b[0m";
$this->ab .= "\x1b[39m";
$this->ab .= ANSI::RESET_TEXT;
$this->ab .= ANSI::color(Color::FG_WHITE);
}
$this->ab .= "\x1b[K"; // Clear the current line
$this->ab .= ANSI::CLEAR_LINE;
$this->ab .= "\r\n";
}
}
protected function drawStatusBar(): void
{
$this->ab .= "\x1b[7m";
$this->ab .= ANSI::color(Color::INVERT);
$statusFilename = $this->filename !== '' ? $this->filename : '[No Name]';
$syntaxType = ($this->syntax !== NULL) ? $this->syntax->filetype : 'no ft';
@ -671,13 +672,13 @@ class Editor {
$this->ab .= ' ';
$len++;
}
$this->ab .= "\x1b[m";
$this->ab .= ANSI::RESET_TEXT;
$this->ab .= "\r\n";
}
protected function drawMessageBar(): void
{
$this->ab .= "\x1b[K";
$this->ab .= ANSI::CLEAR_LINE;
$len = strlen($this->statusMsg);
if ($len > $this->screenCols)
{
@ -696,20 +697,20 @@ class Editor {
$this->ab = '';
$this->ab .= "\x1b[?25l"; // Hide the cursor
$this->ab .= "\x1b[H"; // Reposition cursor to top-left
$this->ab .= ANSI::HIDE_CURSOR;
$this->ab .= ANSI::RESET_CURSOR;
$this->drawRows();
$this->drawStatusBar();
$this->drawMessageBar();
// Specify the current cursor position
$this->ab .= sprintf("\x1b[%d;%dH",
$this->ab .= ANSI::moveCursor(
($this->cursorY - $this->rowOffset) + 1,
($this->renderX - $this->colOffset) + 1
);
$this->ab .= "\x1b[?25h"; // Show the cursor
$this->ab .= ANSI::SHOW_CURSOR;
echo $this->ab;
}
@ -855,8 +856,8 @@ class Editor {
$quit_times--;
return '';
}
write_stdout("\x1b[2J"); // Clear the screen
write_stdout("\x1b[H"); // Reposition cursor to top-left
write_stdout(ANSI::CLEAR_SCREEN);
write_stdout(ANSI::RESET_CURSOR);
return NULL;
break;

View File

@ -319,11 +319,6 @@ class Row {
$char = $this->render[$i];
$prevHl = ($i > 0) ? $this->hl[$i - 1] : Highlight::NORMAL;
if ($this->parent->syntax === NULL)
{
return;
}
// Single-line comments
if ($scsLen > 0 && $inString === '' && $inComment === FALSE
&& substr($this->render, $i, $scsLen) === $scs)
@ -384,7 +379,7 @@ class Row {
continue;
}
if ( $char === '""' || $char === '\'')
if ( $char === '"' || $char === '\'')
{
$inString = $char;
$this->hl[$i] = Highlight::STRING;
@ -441,7 +436,9 @@ class Row {
$this->hlOpenComment = $inComment;
if ($changed && $this->idx + 1 < $this->parent->numRows)
{
// @codeCoverageIgnoreStart
$this->parent->rows[$this->idx + 1]->updateSyntax();
// @codeCoverageIgnoreEnd
}
}
@ -456,7 +453,9 @@ class Row {
$this->idx < $this->parent->numRows
))
{
// @codeCoverageIgnoreStart
return;
// @codeCoverageIgnoreEnd
}
$tokens = $this->parent->tokens[$rowNum];
@ -471,7 +470,9 @@ class Row {
{
if ($offset >= $this->rsize)
{
// @codeCoverageIgnoreStart
break;
// @codeCoverageIgnoreEnd
}
// A multi-line comment can end in the middle of a line...
@ -497,7 +498,9 @@ class Row {
$charLen = strlen($char);
if ($charLen === 0 || $offset >= $this->rsize)
{
// @codeCoverageIgnoreStart
continue;
// @codeCoverageIgnoreEnd
}
$charStart = strpos($this->render, $char, $offset);
if ($charStart === FALSE)
@ -581,7 +584,9 @@ class Row {
$this->hlOpenComment = $inComment;
if ($changed && $this->idx + 1 < $this->parent->numRows)
{
// @codeCoverageIgnoreStart
$this->parent->rows[$this->idx + 1]->updateSyntax();
// @codeCoverageIgnoreEnd
}
}
}

View File

@ -80,9 +80,10 @@ class Termios {
{
$instance = self::getInstance();
write_stdout("\x1b[2J"); // Clear the screen
write_stdout("\x1b[H"); // Reposition cursor to top-left
echo "\n";
// Cleanup
write_stdout(ANSI::CLEAR_SCREEN);
write_stdout(ANSI::RESET_CURSOR);
write_stdout("\n"); // New line, please
$res = get_ffi()->tcsetattr(C::STDIN_FILENO, C::TCSAFLUSH, FFI::addr($instance->originalTermios));

View File

@ -11,6 +11,13 @@
#define FFI_SCOPE "terminal"
#define FFI_LIB "libc.so.6"
// Nonsense for a test with a single quote
// Ignored by PHP due to the octothorpe (#)
#if 0
# char* x = "String with \" escape char";
# char y = 'q';
#endif
// -----------------------------------------------------------------------------
//! <termios.h>
// -----------------------------------------------------------------------------

View File

@ -5,6 +5,17 @@ namespace Aviat\Kilo\Tests\Traits;
use Aviat\Kilo\Editor;
use PHPUnit\Framework\TestCase;
use Spatie\Snapshots\MatchesSnapshots;
use function Aviat\Kilo\get_window_size;
class MockEditor extends Editor {
public function __set(string $key, $value): void
{
if (property_exists($this, $key))
{
$this->$key = $value;
}
}
}
class EditorTest extends TestCase {
use MatchesSnapshots;
@ -15,7 +26,10 @@ class EditorTest extends TestCase {
{
parent::setUp();
$this->editor = Editor::new();
// Mock the screen size, since that can vary widely
$this->editor = MockEditor::new();
$this->editor->__set('screenRows', 23);
$this->editor->__set('screenCols', 80);
}
public function testSanity(): void
@ -26,14 +40,22 @@ class EditorTest extends TestCase {
public function test__debugInfo(): void
{
$state = json_encode($this->editor->__debugInfo());
$state = json_encode($this->editor->__debugInfo(), JSON_THROW_ON_ERROR);
$this->assertMatchesJsonSnapshot($state);
}
public function testOpenPHP(): void
{
$this->editor->open('test.php');
$state = json_encode($this->editor, JSON_THROW_ON_ERROR);
$this->assertMatchesJsonSnapshot($state);
}
public function testOpen(): void
{
$this->editor->open('test.php');
$state = json_encode($this->editor);
$this->editor->open('src/ffi.h');
$state = json_encode($this->editor, JSON_THROW_ON_ERROR);
$this->assertMatchesJsonSnapshot($state);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff