php - How to set different colors for autotext and user-entered text

I try to set a two different colors - blue color for "command>" and magenta for inputed text, but it not work, because readline_callback_handler_install() and readline() not allows a color codes.
For examples:
- if you run
<?php
readline("\033[35mcommand>");
using cli. you get result like this
- if you try this example
<?php
fputs(STDOUT, "\033[34mcommand>\033[35m");
readline(' ');
you get valid colors, but the 'command>' can be deleted.
I have a solution without readline_* functions, but it hasn't support of autocomplete.
current version of code is:
class Dictionary
{
const EXIT_COMMAND = 'exit';
protected array $classesDictionary = [];
protected array $methodsDictionary = [];
private ?string $command = null;
private ?bool $isRunned = null;
public function init()
{
$this->isRunned = true;
stream_set_blocking(STDIN, false);
stream_set_blocking(STDOUT, false);
$this->initCommandCompletionHandler();
$this->showCmdString();
while($this->isRunned) {
$read = [STDIN];
$write = null;
$except = null;
$streamCounts = stream_select($read, $write, $except, null);
if ($streamCounts) {
readline_callback_read_char();
}
}
}
public function showCmdString()
{
fputs(STDOUT, "\033[34mcommand> ");
$command = fgets(STDIN);
if (!empty(trim($command))) {
fputs(STDOUT, "\033[31mHey! I don't know what are you talking about!");
return false;
$message = "You try to run command '{$command}'";
if (!empty($param)) {
$message .= " with param '{$param}'.";
}
fputs(STDOUT, $message . "\n");
}
}
public function initCommandCompletionHandler()
{
$this->initClassesDictionary();
fputs(STDOUT, "\033[34m");
// Tab btn reaction
readline_completion_function(
function ($currWord, $stringPosition, $cursorInLine) {
fputs(STDOUT, "\033[35m");
$fullLine = readline_info()['line_buffer'];
if (count( explode(' ', $fullLine) ) > 2 ) {
return $this->getArgumentsDescription($fullLine);
}
if (
(strrpos($fullLine, ' ') !== false &&
(
strrpos($fullLine, $currWord) === false ||
strrpos($fullLine, ' ') < strrpos($fullLine, $currWord))
)
) {
return $this->getMethodsList($fullLine);
}
return $this->classesDictionary;
}
);
readline_callback_handler_install('>', function($str) {
echo $str;
});
}
private function getMethodsList(string $fullLine)
{
$arr = array_map(fn($item) => trim($item), explode(' ', $fullLine));
return array_filter(
array_map(
fn($method) => "\033[32m".$method->getName()."\033[34m",
(new \ReflectionClass('App\\Providers\\'.$arr[0].'\\Facade'))
->getMethods(
\ReflectionMethod::IS_PUBLIC |
\ReflectionMethod::IS_STATIC |
\ReflectionMethod::IS_FINAL)
),
fn($methodName) => !in_array(
strtolower($methodName),
[
'__construct',
'__destruct',
'__sleep',
'__wakeup',
'__tostring'
]
)
);
}
private function getArgumentsDescription(string $fullLine)
{
$fullArr = explode(' ', trim($fullLine));
$args = [];
array_map(function($arg) use (&$args) {
$type = ($arg->hasType()) ? $arg->getType()->getName() : 'mixed';
$default = ($arg->isDefaultValueAvailable())
? ($arg->getDefaultValue()) ? 'true' : 'false'
: "\033[31mnot have";
$isNullable = ($arg->hasType())
? ($arg->getType()->allowsNull()) ? 'true' : 'false'
: ' not typed';
$isOptional = ($arg->isOptional()) ? 'true' : 'false';
$isVariadic = ($arg->isVariadic()) ? 'true' : 'false';
$args[$arg->getPosition()] =
"\033[32mposition: \033[33m{$arg->getPosition()}\033[32m;" .
"\033[32m name: \033[33m\${$arg->getName()}\033[32m; " .
"\033[32m type: \033[33m{$type}\033[32m; " .
"\033[32m default value: \033[33m{$default}\033[32m; " .
"\033[32m isNullable: \033[33m{$isNullable}\033[32m; " .
"\033[32m isOptional: \033[33m{$isOptional}\033[32m; " .
"\033[32m isVariadic: \033[33m{$isVariadic}\033[34m";
},
(new \ReflectionClass('App\\Providers\\'.$fullArr[0].'\\Facade'))
->getMethod(end($fullArr))
->getParameters());
return $args;
}
public function readCommand($cmd)
{
if ($cmd === self::EXIT_COMMAND) {
$this->isRunned = false;
fputs(STDOUT, "\033[32m\n");
readline_callback_handler_remove();
}
}
private function initClassesDictionary()
{
$this->classesDictionary = array_filter(
array_map(
fn($dir) => basename($dir),
glob('providers/*', GLOB_ONLYDIR)
),
fn($dir) => !in_array($dir, ['contracts'])
);
$this->classesDictionary[] = self::EXIT_COMMAND;
}
public function executeCommand($command)
{
$param = '';
if (strpos($command, ' ') !== false) {
list ($command, $param) = explode(' ', $command, 2);
}
if (!empty(trim($command))) {
if (!$this->isCommandExists($command)) {
fputs(STDOUT, "Hey! I don't know what are you talking about!\n");
return false;
}
$message = "You try to run command '{$command}'";
if (!empty($param)) {
$message .= " and with param '{$param}'.";
}
fputs(STDOUT, $message . "\n");
}
return true;
}
}
Share solution ↓
Additional Information:
Link To Answer People are also looking for solutions of the problem: foreach() argument must be of type array|object, null given
Didn't find the answer?
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Similar questions
Find the answer in similar questions on our website.
Write quick answer
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.