Page rendering using ANSI support

This commit is contained in:
Deon George
2021-10-02 10:02:21 +10:00
parent a24bba0481
commit b35655a163
5 changed files with 511 additions and 42 deletions

View File

@@ -11,6 +11,127 @@ class Font
protected const MSG_WIDTH = 79;
private string $text = '';
private int $width = 0;
private int $height = 0;
public function __get($key)
{
switch ($key) {
case 'height':
return $this->height;
case 'width':
return $this->width;
default:
throw new \Exception(sprintf('Unknown key %s',$key));
}
}
/**
* Message text, goes after header, and if a logo, to the right of it
*
* @param string $text
*/
public function addText(string $text)
{
$this->text = $text;
$this->dimensions();
}
/**
* Characters used in the font
*
* @return Collection
*/
private function chars(): Collection
{
static $chars = NULL;
if (is_null($chars) && $this->text) {
// Trim any leading/trailing spaces
$text = trim(strtolower($this->text));
$chars = collect();
// Work out the characters we need
foreach (array_unique(str_split($text)) as $c) {
if (! $x=Arr::get(static::FONT,$c))
continue;
$chars->put($c,$x);
}
}
return $chars ?: collect();
}
/**
* Full width of the rendered text
*
* @return void
*/
private function dimensions(): void
{
$chars = $this->chars();
$escape = FALSE;
foreach (str_split(strtolower($this->text)) as $c) {
if ($c == "\x1b") {
$escape = TRUE;
continue;
} elseif ($escape) {
$escape = FALSE;
continue;
}
$this->width += ($x=Arr::get($chars->get($c),0)) ? count($x) : 1;
if ($x)
$this->height = (($y=count($chars->get($c))) > $this->height) ? $y : $this->height;
}
// If the last character is a space, we'll reduce the width
$space = TRUE;
foreach ($chars->get($c) as $line => $x)
if (array_pop($x) != 32) {
$space = FALSE;
break;
}
if ($space)
$this->width--;
}
public function render_line(int $line): string
{
$chars = $this->chars();
$result = '';
$escape = FALSE;
$ansi = FALSE;
foreach (str_split(strtolower($this->text)) as $c) {
if (ord($c) == 0x1b) {
$escape = TRUE;
} elseif ($escape && $c) {
$result .= ANSI::ansi_color(ord($c));
$escape = FALSE;
$ansi = TRUE;
} elseif (($c == ' ') || (! $font_chars=$chars->get($c))) {
$result .= $c;
} else {
foreach (Arr::get($font_chars,$line) as $char)
$result .= chr($char);
}
}
return $result.($ansi ? ANSI::ansi_color(0x0e) : '');
}
/**
* This function will format text to static::MSG_WIDTH, as well as adding the logo.
* It is up to the text to be spaced appropriately to wrap around the icon.
@@ -146,9 +267,9 @@ class Font
for ($line=0;$line<$font_height;$line++) {
if ($line == 0) {
$line_icon_width = $icon_width
->skip(intdiv($result_height,$step)*$step)
->take($step)
->max();
->skip(intdiv($result_height,$step)*$step)
->take($step)
->max();
if ($line_icon_width)
$line_icon_width += ANSI::LOGO_OFFSET_WIDTH+ANSI::LOGO_BUFFER_WIDTH;