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 # End of https://www.gitignore.io/api/vim,emacs,composer,jetbrains+all
kilo.log kilo.log
kilo.exception.log
.phpunit.result.cache .phpunit.result.cache
coverage/ 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'); $editor->setStatusMessage('HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find');
// Input Loop try
while (true)
{ {
$editor->refreshScreen(); // Input Loop
$char = $editor->processKeypress(); while (true)
if ($char === NULL)
{ {
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; return 0;
})($argc, $argv); })($argc, $argv);

View File

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

View File

@ -3,6 +3,7 @@
namespace Aviat\Kilo\Enum; namespace Aviat\Kilo\Enum;
use Aviat\Kilo\Traits; use Aviat\Kilo\Traits;
use function Aviat\Kilo\ctrl_key;
/** /**
* 'Raw' input from stdin * 'Raw' input from stdin
@ -28,4 +29,28 @@ class KeyCode {
public const SPACE = ' '; public const SPACE = ' ';
public const TAB = "\t"; public const TAB = "\t";
public const VERTICAL_TAB = "\v"; 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; namespace Aviat\Kilo\Enum;
use Aviat\Kilo\Traits; use Aviat\Kilo\Traits;
use function Aviat\Kilo\ctrl_key;
/** /**
* Constants representing various control keys * Constants representing various control keys
@ -23,28 +22,4 @@ class KeyType {
public const HOME_KEY = 'HOME'; public const HOME_KEY = 'HOME';
public const PAGE_DOWN = 'PAGE_DOWN'; public const PAGE_DOWN = 'PAGE_DOWN';
public const PAGE_UP = 'PAGE_UP'; 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; 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; use PHPUnit\Framework\TestCase;
class KeyTypeTest extends TestCase { class KeyCodeTest extends TestCase {
public function testSanityCheck(): void public function testSanityCheck(): void
{ {
for ($i = 1; $i < 27; $i++) for ($i = 1; $i < 27; $i++)
@ -14,21 +16,22 @@ class KeyTypeTest extends TestCase {
$ord = $i; $ord = $i;
$expected = chr($ord); $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 public function testNullOnInvalidChar(): void
{ {
$this->assertNull(KeyType::CTRL("\t")); $this->assertNull(KeyCode::CTRL("\t"));
} }
public function testSameOutputOnUpperOrLower(): void public function testSameOutputOnUpperOrLower(): void
{ {
$lower = KeyType::CTRL('v'); $lower = KeyCode::CTRL('v');
$upper = KeyType::CTRL('V'); $upper = KeyCode::CTRL('V');
$this->assertEquals($lower, $upper); $this->assertEquals($lower, $upper);
} }