Fix CTRL method
This commit is contained in:
parent
afd6560db4
commit
b0ea547378
1
.gitignore
vendored
1
.gitignore
vendored
@ -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/
|
||||
|
15
kilo
15
kilo
@ -31,6 +31,8 @@ return (static function (int $argc, array $argv): int {
|
||||
|
||||
$editor->setStatusMessage('HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find');
|
||||
|
||||
try
|
||||
{
|
||||
// Input Loop
|
||||
while (true)
|
||||
{
|
||||
@ -41,6 +43,19 @@ return (static function (int $argc, array $argv): int {
|
||||
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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user