php-kilo/src/Kilo.php

220 lines
5.2 KiB
PHP

<?php declare(strict_types=1);
namespace Aviat\Kilo;
use Aviat\Kilo\Enum\Highlight;
use Aviat\Kilo\Enum\RawKeyCode;
use Aviat\Kilo\Terminal\Enum\Color;
use Aviat\Kilo\Terminal\Enum\Color256;
// -----------------------------------------------------------------------------
// ! App Constants
// -----------------------------------------------------------------------------
const KILO_VERSION = '0.3.0';
const KILO_TAB_STOP = 4;
const KILO_QUIT_TIMES = 3;
const NO_MATCH = -1;
const T_RAW = -1;
// -----------------------------------------------------------------------------
// ! App Config
// -----------------------------------------------------------------------------
/**
* Configure syntax highlighting colors
*/
function get_syntax_color(Highlight $hl): Color | Color256 | int {
return match ($hl)
{
Highlight::Comment => Color::FG_CYAN,
Highlight::MultiLineComment => Color::FG_BRIGHT_BLACK,
Highlight::Keyword1 => Color::FG_YELLOW,
Highlight::Keyword2 => Color::FG_GREEN,
Highlight::String => Color::FG_MAGENTA,
Highlight::Character => Color::FG_BRIGHT_MAGENTA,
Highlight::Number => Color::FG_BRIGHT_RED,
Highlight::Operator => Color::FG_BRIGHT_GREEN,
Highlight::Variable => Color::FG_BRIGHT_CYAN,
Highlight::Delimiter => Color::FG_BLUE,
Highlight::Invalid => Color::BG_BRIGHT_RED,
Highlight::SearchMatch => Color::INVERT,
Highlight::Identifier => Color::FG_BRIGHT_WHITE,
default => Color::FG_WHITE,
};
}
// ----------------------------------------------------------------------------
// ! C function/macro equivalents
// ----------------------------------------------------------------------------
/**
* Do bit twiddling to convert a letter into
* its Ctrl-letter equivalent ordinal ascii value
*/
function ctrl_key(string $char): int
{
if ( ! is_ascii($char))
{
return -1;
}
// b1,100,001 (a) & b0,011,111 (0x1f) = b0,000,001 (SOH)
// b1,100,010 (b) & b0,011,111 (0x1f) = b0,000,010 (STX)
// ...and so on
return ord($char) & 0x1f;
}
/**
* Does the one-character string contain an ascii ordinal value?
*/
function is_ascii(string $single_char): bool
{
if (strlen($single_char) > 1)
{
return FALSE;
}
return ord($single_char) < 0x80;
}
/**
* Does the one-character string contain an ascii control character?
*/
function is_ctrl(string $char): bool
{
$c = ord($char);
return is_ascii($char) && ( $c === 0x7f || $c < 0x20 );
}
/**
* Does the one-character string contain an ascii number?
*/
function is_digit(string $char): bool
{
$c = ord($char);
return is_ascii($char) && ( $c > 0x2f && $c < 0x3a );
}
/**
* Does the one-character string contain ascii whitespace?
*/
function is_space(string $char): bool
{
return match($char) {
RawKeyCode::CARRIAGE_RETURN,
RawKeyCode::FORM_FEED,
RawKeyCode::NEWLINE,
RawKeyCode::SPACE,
RawKeyCode::TAB,
RawKeyCode::VERTICAL_TAB => true,
default => false,
};
}
// ----------------------------------------------------------------------------
// ! Helper functions
// ----------------------------------------------------------------------------
/**
* Does the one-character string contain a character that separates tokens?
*/
function is_separator(string $char): bool
{
if ( ! is_ascii($char))
{
return FALSE;
}
$isSep = str_contains(',.()+-/*=~%<>[];', $char);
return is_space($char) || $char === RawKeyCode::NULL || $isSep;
}
/**
* Replaces a slice of an array with the same value
*
* @param array $array The array to update
* @param int $offset The index of the first location to update
* @param int $length The number of indices to update
* @param mixed $value The value to replace in the range
*/
function array_replace_range(array &$array, int $offset, int $length, mixed $value):void
{
if ($length === 1)
{
$array[$offset] = $value;
return;
}
$replacement = array_fill(0, $length, $value);
array_splice($array, $offset, $length, $replacement);
}
/**
* Does the string $haystack contain $str, optionally searching from $offset
*/
function str_has(string $haystack, string $str, ?int $offset = NULL): bool
{
if (empty($str))
{
return FALSE;
}
return ($offset !== NULL)
? strpos($haystack, $str, $offset) !== FALSE
: \str_contains($haystack, $str);
}
/**
* Replace tabs with the specified number of spaces.
*/
function tabs_to_spaces(string $str, int $number = KILO_TAB_STOP): string
{
return str_replace(RawKeyCode::TAB, str_repeat(RawKeyCode::SPACE, $number), $str);
}
function error_code_name(int $code): string
{
return match ($code) {
E_ERROR => 'Error',
E_WARNING => 'Warning',
E_PARSE => 'Parse Error',
E_NOTICE => 'Notice',
E_CORE_ERROR => 'Core Error',
E_CORE_WARNING => 'Core Warning',
E_COMPILE_ERROR => 'Compile Error',
E_COMPILE_WARNING => 'Compile Warning',
E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice',
E_RECOVERABLE_ERROR => 'Recoverable Error',
E_DEPRECATED => 'Deprecated',
E_USER_DEPRECATED => 'User Deprecated',
default => 'Unknown',
};
}
/**
* Adds two numbers to at most the $max value
*/
function saturating_add(int $a, int $b, int $max): int
{
return ($a + $b > $max) ? $max : $a + $b;
}
/**
* Delete one number from another, down to zero at the least
*/
function saturating_sub(int $a, int $b): int
{
if ($b > $a)
{
return 0;
}
return $a - $b;
}