php-kilo/src/Terminal.php

162 lines
3.1 KiB
PHP

<?php declare(strict_types=1);
namespace Aviat\Kilo;
use Aviat\Kilo\Enum\KeyCode;
use Aviat\Kilo\Enum\KeyType;
use Aviat\Kilo\Type\TerminalSize;
class Terminal {
/**
* Get the size of the current terminal window
*
* @codeCoverageIgnore
* @return TerminalSize
*/
public static function size(): TerminalSize
{
return new TerminalSize(...self::getWindowSize());
}
/**
* Get the size of the current terminal window
*
* @codeCoverageIgnore
* @return array
*/
public static function getWindowSize(): array
{
$ffiSize = Termios::getWindowSize();
if ($ffiSize !== NULL)
{
return $ffiSize;
}
// Try using tput
if (self::has_tput())
{
$rows = (int)trim((string)shell_exec('tput lines'));
$cols = (int)trim((string)shell_exec('tput cols'));
if ($rows > 0 && $cols > 0)
{
return [$rows, $cols];
}
}
// Worst-case, return an arbitrary 'standard' size
return [25, 80];
}
/**
* Clear the screen and reset the cursor position
*/
public static function clear(): void
{
self::write(ANSI::CLEAR_SCREEN . ANSI::RESET_CURSOR);
}
/**
* Pull input from the stdin stream.
*
* @codeCoverageIgnore
* @param int $len
* @return string
*/
public static function read(int $len = 128): string
{
$handle = fopen('php://stdin', 'rb');
if ($handle === false)
{
return '';
}
$input = fread($handle, $len);
fclose($handle);
return (is_string($input)) ? $input : '';
}
/**
* Get the last key input from the terminal and convert to a
* more useful format
*
* @return string
*/
public static function readKey(): string
{
$c = Terminal::read();
return match($c)
{
// 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::DEL_KEY => KeyType::DEL_KEY,
KeyCode::ENTER => KeyType::ENTER,
KeyCode::PAGE_DOWN => KeyType::PAGE_DOWN,
KeyCode::PAGE_UP => KeyType::PAGE_UP,
// Backspace
KeyCode::CTRL('h'), KeyCode::BACKSPACE => KeyType::BACKSPACE,
// Escape
KeyCode::CTRL('l'), KeyCode::ESCAPE => KeyType::ESCAPE,
// Home Key
"\eOH", "\e[7~", "\e[1~", ANSI::RESET_CURSOR => KeyType::HOME_KEY,
// End Key
"\eOF", "\e[4~", "\e[8~", "\e[F" => KeyType::END_KEY,
default => $c,
};
}
/**
* Write to the stdout stream
*
* @codeCoverageIgnore
* @param string $str
* @param int|NULL $len
* @return int|false
*/
public static function write(string $str, int $len = NULL): int|false
{
$handle = fopen('php://stdout', 'ab');
if ($handle === false)
{
return false;
}
$res = (is_int($len))
? fwrite($handle, $str, $len)
: fwrite($handle, $str);
fflush($handle);
fclose($handle);
return $res;
}
/**
* See if tput exists for fallback terminal size detection
*
* @return bool
* @codeCoverageIgnore
*/
private static function has_tput(): bool
{
$cmd = shell_exec('type tput');
if ( ! is_string($cmd))
{
return FALSE;
}
return str_contains($cmd, ' is ');
}
}