- Added color / formats management
This commit is contained in:
parent
d503628356
commit
32d5079559
@ -3,6 +3,7 @@
|
||||
namespace Mcnd\CLI;
|
||||
|
||||
use Laminas\Diactoros\Response\TextResponse;
|
||||
use Mcnd\CLI\Lib\AsciiFormatter;
|
||||
use Notes\CLI\CommandFetcher;
|
||||
|
||||
use Psr\Http\Message\ResponseFactoryInterface,
|
||||
@ -14,6 +15,8 @@ use Psr\Http\Message\ResponseFactoryInterface,
|
||||
|
||||
class CliMiddleware implements MiddlewareInterface
|
||||
{
|
||||
public bool $allowAsciiFormatting;
|
||||
|
||||
public \Closure $defaultResponse;
|
||||
|
||||
public ContainerInterface $container;
|
||||
@ -28,11 +31,12 @@ class CliMiddleware implements MiddlewareInterface
|
||||
|
||||
protected array $parsedOptions = [];
|
||||
|
||||
public function __construct(ContainerInterface $container, callable $defaultResponseInterface = null, null|CommandFetcher $fetcher = null, null|CommandStack $stack = null) {
|
||||
public function __construct(ContainerInterface $container, callable $defaultResponseInterface = null, null|CommandFetcher $fetcher = null, null|CommandStack $stack = null, bool $allowAsciiFormatting = true) {
|
||||
$this->defaultResponse = $defaultResponseInterface;
|
||||
$this->container = $container;
|
||||
$this->fetcher = $fetcher;
|
||||
$this->commands = $stack ?? new CommandStack();
|
||||
$this->allowAsciiFormatting = $allowAsciiFormatting;
|
||||
}
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
|
||||
@ -59,7 +63,6 @@ class CliMiddleware implements MiddlewareInterface
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return call_user_func($this->defaultResponse);
|
||||
}
|
||||
|
||||
@ -85,6 +88,10 @@ class CliMiddleware implements MiddlewareInterface
|
||||
" COMMANDS HERE", "",
|
||||
];
|
||||
|
||||
if ($this->allowAsciiFormatting) {
|
||||
$text = ( new AsciiFormatter() )->parse($text);
|
||||
}
|
||||
|
||||
return new TextResponse( implode(PHP_EOL, $text) );
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Mcnd\CLI;
|
||||
|
||||
#[\Attribute]
|
||||
class Command
|
||||
{
|
||||
public function __construct(
|
||||
|
95
src/Lib/AsciiFormatter.php
Normal file
95
src/Lib/AsciiFormatter.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Mcnd\CLI\Lib;
|
||||
|
||||
class AsciiFormatter
|
||||
{
|
||||
public array $stack = [];
|
||||
|
||||
protected string $latest;
|
||||
|
||||
public function parse(array|string $content) : array|string
|
||||
{
|
||||
return is_array($content) ? array_map([ $this, 'parseContent' ], $content) : $this->parseContent($content);
|
||||
}
|
||||
|
||||
protected function parseContent(string $text) : string
|
||||
{
|
||||
if (str_contains($text, '#[')) {
|
||||
# Opening 'tag'
|
||||
$text = preg_replace_callback("#(\#\[)(.*?)(\])#s", function ($matches) {
|
||||
if ( empty($stack) ) {
|
||||
$this->stack[] = $this->translateFormat("c:default, bg:default, f:normal");
|
||||
}
|
||||
else {
|
||||
$this->stack[] = $this->latest;
|
||||
}
|
||||
|
||||
$this->latest = $this->translateFormat($matches[2]);
|
||||
|
||||
return $this->latest;
|
||||
}, $text);
|
||||
|
||||
# Closing 'tag'
|
||||
$text = preg_replace_callback("#(\[\#\])#s", function ($matches) {
|
||||
$close = $this->stack ? array_pop($this->stack) : "";
|
||||
|
||||
return $close;
|
||||
}, $text);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
protected function translateFormat(string $source) : string
|
||||
{
|
||||
$valueType =
|
||||
$color = $background = $format = null;
|
||||
|
||||
foreach(array_map(fn($e) => trim(strtolower($e)), explode(',', $source)) as $formatting) {
|
||||
if ( ! strstr($formatting, ':' )) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("Arguments must be called with their variable's name (%s)", $formatting)
|
||||
);
|
||||
}
|
||||
|
||||
list($scope, $value) = explode(':', $formatting, 2);
|
||||
|
||||
switch($scope) {
|
||||
case 'color':
|
||||
case 'c':
|
||||
$type = ValueTypeEnum::autodetect($value);
|
||||
|
||||
if ($type === ValueTypeEnum::Ascii16) {
|
||||
$color = ColorEnum::mapFrom($value);
|
||||
}
|
||||
elseif ($type === ValueTypeEnum::Ascii256) {
|
||||
$color = RgbColor::mapFrom($value);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'background':
|
||||
case 'bg':
|
||||
case 'b':
|
||||
$type = ValueTypeEnum::autodetect($value);
|
||||
|
||||
if ($type === ValueTypeEnum::Ascii16) {
|
||||
$background = BackgroundColorEnum::mapFrom($value);
|
||||
}
|
||||
elseif ($type === ValueTypeEnum::Ascii256) {
|
||||
$background = RgbBackground::mapFrom($value);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'format':
|
||||
case 'f':
|
||||
$format = FormatEnum::mapFrom($value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ($color ? $color->output() : "") . ($background ? $background->output() : "") . ($format ? $format->output() : "");
|
||||
}
|
||||
}
|
26
src/Lib/BackgroundColorEnum.php
Normal file
26
src/Lib/BackgroundColorEnum.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Mcnd\CLI\Lib;
|
||||
|
||||
enum BackgroundColorEnum : string
|
||||
{
|
||||
use ColorMappingTrait;
|
||||
|
||||
case Default = "49";
|
||||
case Black = "40";
|
||||
case Red = "41";
|
||||
case Green = "42";
|
||||
case Yellow = "43";
|
||||
case Blue = "44";
|
||||
case Magenta = "45";
|
||||
case Cyan = "46";
|
||||
case LightGray = "47";
|
||||
case DarkGray = "100";
|
||||
case LightRed = "101";
|
||||
case LightGreen = "102";
|
||||
case LightYellow = "103";
|
||||
case LightBlue = "104";
|
||||
case LightMagenta = "105";
|
||||
case LightCyan = "106";
|
||||
case White = "107";
|
||||
}
|
26
src/Lib/ColorEnum.php
Normal file
26
src/Lib/ColorEnum.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Mcnd\CLI\Lib;
|
||||
|
||||
enum ColorEnum : string
|
||||
{
|
||||
use ColorMappingTrait;
|
||||
|
||||
case Default = "39";
|
||||
case Black = "30";
|
||||
case Red = "31";
|
||||
case Green = "32";
|
||||
case Yellow = "33";
|
||||
case Blue = "34";
|
||||
case Magenta = "35";
|
||||
case Cyan = "36";
|
||||
case LightGray = "37";
|
||||
case DarkGray = "90";
|
||||
case LightRed = "91";
|
||||
case LightGreen = "92";
|
||||
case LightYellow = "93";
|
||||
case LightBlue = "94";
|
||||
case LightMagenta = "95";
|
||||
case LightCyan = "96";
|
||||
case White = "97";
|
||||
}
|
33
src/Lib/ColorMappingTrait.php
Normal file
33
src/Lib/ColorMappingTrait.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Mcnd\CLI\Lib;
|
||||
|
||||
trait ColorMappingTrait
|
||||
{
|
||||
public static function mapFrom(string $name) : ? self
|
||||
{
|
||||
return [
|
||||
'black' => self::Black,
|
||||
'red' => self::Red,
|
||||
'green' => self::Green,
|
||||
'yellow' => self::Yellow,
|
||||
'blue' => self::Blue,
|
||||
'magenta' => self::Magenta,
|
||||
'cyan' => self::Cyan,
|
||||
'lightgray' => self::LightGray,
|
||||
'darkgray' => self::DarkGray,
|
||||
'lightred' => self::LightRed,
|
||||
'lightgreen' => self::LightGreen,
|
||||
'lightyellow' => self::LightYellow,
|
||||
'lightblue' => self::LightBlue,
|
||||
'lightmagenta' => self::LightMagenta,
|
||||
'lightcyan' => self::LightCyan,
|
||||
'white' => self::White,
|
||||
][$name] ?? null;
|
||||
}
|
||||
|
||||
public function output() : string
|
||||
{
|
||||
return "\e[{$this->value}m";
|
||||
}
|
||||
}
|
39
src/Lib/FormatEnum.php
Normal file
39
src/Lib/FormatEnum.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Mcnd\CLI\Lib;
|
||||
|
||||
enum FormatEnum : string
|
||||
{
|
||||
case Normal = "0";
|
||||
case Bold = "1";
|
||||
case Dim = "2";
|
||||
case Italic = "3";
|
||||
case Underlined = "4";
|
||||
case Blinking = "5";
|
||||
case Reverse = "7";
|
||||
case Invisible = "8";
|
||||
|
||||
public static function mapFrom(string $name): ?self
|
||||
{
|
||||
return [
|
||||
'n' => self::Normal,
|
||||
'normal' => self::Normal,
|
||||
'b' => self::Bold,
|
||||
'bold' => self::Bold,
|
||||
'd' => self::Dim,
|
||||
'dim' => self::Dim,
|
||||
'i' => self::Italic,
|
||||
'italic' => self::Italic,
|
||||
'u' => self::Underlined,
|
||||
'underlined' => self::Underlined,
|
||||
'blinking' => self::Blinking,
|
||||
'reverse' => self::Reverse,
|
||||
'invisible' => self::Invisible,
|
||||
][$name] ?? null;
|
||||
}
|
||||
|
||||
public function output() : string
|
||||
{
|
||||
return "\e[{$this->value}m";
|
||||
}
|
||||
}
|
11
src/Lib/RgbBackground.php
Normal file
11
src/Lib/RgbBackground.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Mcnd\CLI\Lib;
|
||||
|
||||
class RgbBackground extends RgbColor
|
||||
{
|
||||
public function output() : string
|
||||
{
|
||||
return "\033[48;2;{$this->rgb}m";
|
||||
}
|
||||
}
|
28
src/Lib/RgbColor.php
Normal file
28
src/Lib/RgbColor.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Mcnd\CLI\Lib;
|
||||
|
||||
class RgbColor
|
||||
{
|
||||
public readonly string $rgb;
|
||||
|
||||
public function __construct(int $red, int $green, int $blue)
|
||||
{
|
||||
$this->rgb = "$red;$green;$blue";
|
||||
}
|
||||
|
||||
public static function mapFrom(string $value) : ? self
|
||||
{
|
||||
$begin = strpos($value, 'rgb(') + 4;
|
||||
$end = strrpos($value, ')');
|
||||
|
||||
$rgb = substr($value, $begin, $end - $begin);
|
||||
|
||||
return new static(...explode(';', $rgb));
|
||||
}
|
||||
|
||||
public function output() : string
|
||||
{
|
||||
return "\033[38;2;{$this->rgb}m";
|
||||
}
|
||||
}
|
28
src/Lib/ValueTypeEnum.php
Normal file
28
src/Lib/ValueTypeEnum.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Mcnd\CLI\Lib;
|
||||
|
||||
enum ValueTypeEnum
|
||||
{
|
||||
case NoColors;
|
||||
case Ascii16;
|
||||
case Ascii256;
|
||||
|
||||
public static function autodetect(string $value) : self
|
||||
{
|
||||
if ( substr($value, 0, 4) === 'rgb(' ) {
|
||||
if (! strstr($value, ')')) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf("An unclosed parenthesis was found for 'rgb' color %s", $value)
|
||||
);
|
||||
}
|
||||
|
||||
return self::Ascii256;
|
||||
}
|
||||
elseif ( ColorEnum::mapFrom($value) !== null || BackgroundColorEnum::mapFrom($value) ) {
|
||||
return self::Ascii16;
|
||||
}
|
||||
|
||||
return self::NoColors;
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Mcnd\CLI;
|
||||
|
||||
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_CLASS)]
|
||||
class Option
|
||||
{
|
||||
public const ARGUMENT_NONE = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user