Fix CTRL method

This commit is contained in:
Timothy Warren 2020-02-05 16:32:17 -05:00
parent afd6560db4
commit b0ea547378
6 changed files with 81 additions and 64 deletions

1
.gitignore vendored
View File

@ -169,5 +169,6 @@ tags
# End of https://www.gitignore.io/api/vim,emacs,composer,jetbrains+all
kilo.log
kilo.exception.log
.phpunit.result.cache
coverage/

27
kilo
View File

@ -31,16 +31,31 @@ return (static function (int $argc, array $argv): int {
$editor->setStatusMessage('HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find');
// Input Loop
while (true)
try
{
$editor->refreshScreen();
$char = $editor->processKeypress();
if ($char === NULL)
// Input Loop
while (true)
{
break;
$editor->refreshScreen();
$char = $editor->processKeypress();
if ($char === NULL)
{
break;
}
}
}
catch (\Throwable $e)
{
$msg = print_r([
'code' => $e->getCode(),
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString(),
], TRUE);
file_put_contents('kilo.exception.log', $msg, FILE_APPEND);
}
return 0;
})($argc, $argv);

View File

@ -88,42 +88,38 @@ class Editor {
{
$c = read_stdin();
$simpleMap = [
$map = [
// Unambiguous mappings
KeyCode::ARROW_DOWN => KeyType::ARROW_DOWN,
KeyCode::ARROW_LEFT => KeyType::ARROW_LEFT,
KeyCode::ARROW_RIGHT => KeyType::ARROW_RIGHT,
KeyCode::ARROW_UP => KeyType::ARROW_UP,
KeyCode::BACKSPACE => KeyType::BACKSPACE,
KeyCode::DEL_KEY => KeyType::DEL_KEY,
KeyCode::ENTER => KeyType::ENTER,
KeyCode::ESCAPE => KeyType::ESCAPE,
KeyCode::PAGE_DOWN => KeyType::PAGE_DOWN,
KeyCode::PAGE_UP => KeyType::PAGE_UP,
];
$multiMap = [
// Backspace
KeyCode::CTRL('h') => KeyType::BACKSPACE,
KeyCode::BACKSPACE => KeyType::BACKSPACE,
// Home Key
"\eOH" => KeyType::HOME_KEY,
"\e[1~" => KeyType::HOME_KEY,
"\e[7~" => KeyType::HOME_KEY,
ANSI::RESET_CURSOR => KeyType::HOME_KEY,
// End Key
"\eOF" => KeyType::END_KEY,
"\e[4~" => KeyType::END_KEY,
"\e[8~" => KeyType::END_KEY,
"\e[F" => KeyType::END_KEY,
];
if (array_key_exists($c, $simpleMap))
{
return $simpleMap[$c];
}
if (array_key_exists($c, $multiMap))
{
return $multiMap[$c];
}
return $c;
return (array_key_exists($c, $map))
? $map[$c]
: $c;
}
protected function selectSyntaxHighlight(): void
@ -448,18 +444,20 @@ class Editor {
$current = 0;
}
$match = strpos($this->rows[$current]->render, $query);
$row =& $this->rows[$current];
$match = strpos($row->render, $query);
if ($match !== FALSE)
{
$lastMatch = $current;
$this->cursorY = $current;
$this->cursorX = $this->rowRxToCx($this->rows[$current], $match);
$this->cursorX = $this->rowRxToCx($row, $match);
$this->rowOffset = $this->numRows;
$savedHlLine = $current;
$savedHl = $this->rows[$current]->hl;
$savedHl = $row->hl;
// Update the highlight array of the relevant row with the 'MATCH' type
array_replace_range($this->rows[$current]->hl, $match, strlen($query), Highlight::MATCH);
array_replace_range($row->hl, $match, strlen($query), Highlight::MATCH);
break;
}
@ -710,6 +708,7 @@ class Editor {
$this->refreshScreen();
$c = $this->readKey();
$isModifier = in_array($c, $modifiers, TRUE);
if ($c === KeyType::ESCAPE || ($c === KeyType::ENTER && $buffer !== ''))
{
@ -721,11 +720,11 @@ class Editor {
return '';
}
if ($c === KeyType::DEL_KEY || $c === KeyType::BACKSPACE || KeyType::CTRL('h'))
if ($c === KeyType::DEL_KEY || $c === KeyType::BACKSPACE)
{
$buffer = substr($buffer, 0, -1);
}
else if (is_ascii($c) && ( ! is_ctrl($c)) && ! in_array($c, $modifiers, TRUE))
else if (is_ascii($c) && ( ! (is_ctrl($c) || $isModifier)))
{
$buffer .= $c;
}
@ -811,7 +810,7 @@ class Editor {
$this->insertNewline();
break;
case KeyType::CTRL('q'):
case KeyCode::CTRL('q'):
if ($this->dirty > 0 && $quit_times > 0)
{
$this->setStatusMessage('WARNING!!! File has unsaved changes.' .
@ -824,7 +823,7 @@ class Editor {
return NULL;
break;
case KeyType::CTRL('s'):
case KeyCode::CTRL('s'):
$this->save();
break;
@ -839,12 +838,11 @@ class Editor {
}
break;
case KeyType::CTRL('f'):
case KeyCode::CTRL('f'):
$this->find();
break;
case KeyType::BACKSPACE:
case KeyType::CTRL('h'):
case KeyType::DEL_KEY:
if ($c === KeyType::DEL_KEY)
{
@ -865,7 +863,7 @@ class Editor {
$this->moveCursor($c);
break;
case KeyType::CTRL('l'):
case KeyCode::CTRL('l'):
case KeyType::ESCAPE:
// Do nothing
break;

View File

@ -3,6 +3,7 @@
namespace Aviat\Kilo\Enum;
use Aviat\Kilo\Traits;
use function Aviat\Kilo\ctrl_key;
/**
* 'Raw' input from stdin
@ -28,4 +29,28 @@ class KeyCode {
public const SPACE = ' ';
public const TAB = "\t";
public const VERTICAL_TAB = "\v";
/**
* Returns the ascii character for the specified
* ctrl + letter combo
*
* @param string $char
* @return string
*/
public static function CTRL(string $char): ?string
{
$char = strtolower($char);
$ord = ord($char);
// a = 0x61
// z = 0x7a
// So, 0x60 < $ord < 0x7b
if ($ord > 0x60 && $ord < 0x7b)
{
return chr(ctrl_key($char));
}
// Invalid input, not an ascii letter
return NULL;
}
}

View File

@ -3,7 +3,6 @@
namespace Aviat\Kilo\Enum;
use Aviat\Kilo\Traits;
use function Aviat\Kilo\ctrl_key;
/**
* Constants representing various control keys
@ -23,28 +22,4 @@ class KeyType {
public const HOME_KEY = 'HOME';
public const PAGE_DOWN = 'PAGE_DOWN';
public const PAGE_UP = 'PAGE_UP';
/**
* Returns the ascii character for the specified
* ctrl + letter combo
*
* @param string $char
* @return string
*/
public static function CTRL(string $char): ?string
{
$char = strtolower($char);
$ord = ord($char);
// a = 0x61
// z = 0x7a
// So, 0x60 < $ord < 0x7b
if ($ord > 0x60 && $ord < 0x7b)
{
return chr(ctrl_key($char));
}
// Invalid input, not an ascii letter
return NULL;
}
}

View File

@ -2,10 +2,12 @@
namespace Aviat\Kilo\Tests\Enum;
use Aviat\Kilo\Enum\KeyType;
use function Aviat\Kilo\ctrl_key;
use Aviat\Kilo\Enum\KeyCode;
use PHPUnit\Framework\TestCase;
class KeyTypeTest extends TestCase {
class KeyCodeTest extends TestCase {
public function testSanityCheck(): void
{
for ($i = 1; $i < 27; $i++)
@ -14,21 +16,22 @@ class KeyTypeTest extends TestCase {
$ord = $i;
$expected = chr($ord);
$actual = KeyType::CTRL($char);
$actual = KeyCode::CTRL($char);
$this->assertEquals($expected, $actual, "CTRL + '{$char}' should return chr($ord)");
$this->assertEquals(ctrl_key($char), $ord, "chr(ctrl_key) !== CTRL");
$this->assertEquals($expected, $actual, "CTRL+'{$char}' should return chr($ord)");
}
}
public function testNullOnInvalidChar(): void
{
$this->assertNull(KeyType::CTRL("\t"));
$this->assertNull(KeyCode::CTRL("\t"));
}
public function testSameOutputOnUpperOrLower(): void
{
$lower = KeyType::CTRL('v');
$upper = KeyType::CTRL('V');
$lower = KeyCode::CTRL('v');
$upper = KeyCode::CTRL('V');
$this->assertEquals($lower, $upper);
}