Skip to content
This repository was archived by the owner on Jan 23, 2019. It is now read-only.

Commit f98f2f8

Browse files
committed
update cli color render
1 parent d810baf commit f98f2f8

File tree

6 files changed

+247
-66
lines changed

6 files changed

+247
-66
lines changed

examples/cli-color.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
/**
3+
* Created by PhpStorm.
4+
* User: inhere
5+
* Date: 2017/10/21
6+
* Time: 上午12:48
7+
*/
8+
9+
use Inhere\Library\Helpers\Cli;
10+
11+
require __DIR__ . '/s-autoload.php';
12+
13+
echo Cli::color('message text', [Cli::FG_BLACK, Cli::BG_BLUE]), PHP_EOL;
14+
echo Cli::color('message text', 'light_blue'), PHP_EOL;
15+
echo Cli::color('message text', 'light_green'), PHP_EOL;
16+
echo Cli::color('message text', 'light_cyan'), PHP_EOL;
17+
echo Cli::color('message text', Cli::FG_LIGHT_GREEN), PHP_EOL;
18+
19+
echo "------------------------------------\n";
20+
21+
echo Cli::color(<<<TAG
22+
<info>info color</info>
23+
<suc>info color</suc>
24+
<error>info color</error>
25+
<danger>info color</danger>
26+
<warning>info color</warning>
27+
------------------------------------
28+
TAG
29+
);
30+
31+
Cli::write(<<<TAG
32+
\n<info>info color</info>
33+
<suc>info color</suc>
34+
<error>info color</error>
35+
<danger>info color</danger>
36+
<warning>info color</warning>
37+
TAG
38+
);

examples/cli-color.png

50.3 KB
Loading

examples/di.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
require __DIR__ . '/s-autoload.php';
1313

1414
$di = new Container([
15-
'logger' => LiteLogger::make([], 'test'),
15+
'logger' => LiteLogger::make(['name' => 'test']),
1616
'logger2' => [
1717
'target' => LiteLogger::class . '::make',
1818
['name' => 'test2']// first arg

src/Helpers/Cli.php

Lines changed: 155 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -20,35 +20,62 @@ class Cli
2020
const FG_BLACK = 30;
2121
const FG_RED = 31;
2222
const FG_GREEN = 32;
23-
const FG_BROWN = 33;
23+
const FG_BROWN = 33; // like yellow
2424
const FG_BLUE = 34;
2525
const FG_CYAN = 36;
2626
const FG_WHITE = 37;
2727
const FG_DEFAULT = 39;
2828

29+
// extra Foreground color
30+
const FG_DARK_GRAY = 90;
31+
const FG_LIGHT_RED = 91;
32+
const FG_LIGHT_GREEN = 92;
33+
const FG_LIGHT_YELLOW = 93;
34+
const FG_LIGHT_BLUE = 94;
35+
const FG_LIGHT_MAGENTA = 95;
36+
const FG_LIGHT_CYAN = 96;
37+
const FG_WHITE_W = 97;
38+
2939
// Background color
3040
const BG_BLACK = 40;
3141
const BG_RED = 41;
3242
const BG_GREEN = 42;
33-
const BG_BROWN = 43;
43+
const BG_BROWN = 43; // like yellow
3444
const BG_BLUE = 44;
3545
const BG_CYAN = 46;
3646
const BG_WHITE = 47;
3747
const BG_DEFAULT = 49;
3848

49+
// extra Background color
50+
const BG_DARK_GRAY = 100;
51+
const BG_LIGHT_RED = 101;
52+
const BG_LIGHT_GREEN = 102;
53+
const BG_LIGHT_YELLOW = 103;
54+
const BG_LIGHT_BLUE = 104;
55+
const BG_LIGHT_MAGENTA = 105;
56+
const BG_LIGHT_CYAN = 106;
57+
const BG_WHITE_W = 107;
58+
3959
// color option
4060
const BOLD = 1; // 加粗
4161
const FUZZY = 2; // 模糊(不是所有的终端仿真器都支持)
4262
const ITALIC = 3; // 斜体(不是所有的终端仿真器都支持)
43-
const UNDERSCORE = 4; // 下划线
63+
const UNDERSCORE = 4; // 下划线
4464
const BLINK = 5; // 闪烁
45-
const REVERSE = 7; // 颠倒的 交换背景色与前景色
65+
const REVERSE = 7; // 颠倒的 交换背景色与前景色
66+
const CONCEALED = 8; // 隐匿的
67+
68+
/**
69+
* Regex to match tags
70+
* @var string
71+
*/
72+
const COLOR_TAG = '/<([a-z=;]+)>(.*?)<\/\\1>/s';
4673

4774
/**
4875
* some styles
4976
* @var array
5077
*/
51-
public static $styles = [
78+
const STYLES = [
5279
'light_red' => '1;31',
5380
'light_green' => '1;32',
5481
'yellow' => '1;33',
@@ -62,36 +89,84 @@ class Cli
6289
'brown' => '0;33',
6390
'blue' => '0;34',
6491
'cyan' => '0;36',
92+
6593
'bold' => '1',
6694
'underscore' => '4',
6795
'reverse' => '7',
96+
97+
//
98+
'suc' => '1;32',// same 'green' and 'bold'
99+
'success' => '1;32',
100+
'info' => '0;32',// same 'green'
101+
'comment' => '0;33',// same 'brown'
102+
'warning' => '0;30;43',
103+
'danger' => '0;31',// same 'red'
104+
'error' => '30;41',
68105
];
69106

107+
/*******************************************************************************
108+
* color render
109+
******************************************************************************/
110+
70111
/**
71112
* @param $text
72113
* @param string|int|array $style
73114
* @return string
74115
*/
75-
public static function color($text, $style = self::NORMAL)
116+
public static function color($text, $style = null)
76117
{
77-
if (!self::isSupportColor()) {
118+
if (!$text) {
78119
return $text;
79120
}
80121

122+
if (!self::isSupportColor()) {
123+
return self::clearColor($text);
124+
}
125+
81126
if (is_string($style)) {
82-
$out = self::$styles[$style] ?? '0';
127+
$color = self::STYLES[$style] ?? '0';
83128
} elseif (is_int($style)) {
84-
$out = $style;
129+
$color = $style;
85130

86131
// array: [self::FG_GREEN, self::BG_WHITE, self::UNDERSCORE]
87132
} elseif (is_array($style)) {
88-
$out = implode(';', $style);
133+
$color = implode(';', $style);
134+
} elseif (strpos($text, '<') !== false) {
135+
return self::renderColor($text);
89136
} else {
90-
$out = self::NORMAL;
137+
return $text;
138+
}
139+
140+
// $result = chr(27). "$color{$text}" . chr(27) . chr(27) . "[0m". chr(27);
141+
return "\033[{$color}m{$text}\033[0m";
142+
}
143+
144+
public static function renderColor($text)
145+
{
146+
if (!$text || false === strpos($text, '<')) {
147+
return $text;
148+
}
149+
150+
// if don't support output color text, clear color tag.
151+
if (!EnvHelper::isSupportColor()) {
152+
return static::clearColor($text);
153+
}
154+
155+
if (!preg_match_all(self::COLOR_TAG, $text, $matches)) {
156+
return $text;
157+
}
158+
159+
foreach ((array)$matches[0] as $i => $m) {
160+
if ($style = self::STYLES[$matches[1][$i]] ?? null) {
161+
$tag = $matches[1][$i];
162+
$match = $matches[2][$i];
163+
164+
$replace = sprintf("\033[%sm%s\033[0m", $style, $match);
165+
$text = str_replace("<$tag>$match</$tag>", $replace, $text);
166+
}
91167
}
92168

93-
// $result = chr(27). "$out{$text}" . chr(27) . chr(27) . "[0m". chr(27);
94-
return "\033[{$out}m{$text}\033[0m";
169+
return $text;
95170
}
96171

97172
/**
@@ -101,41 +176,85 @@ public static function color($text, $style = self::NORMAL)
101176
public static function clearColor($text)
102177
{
103178
// return preg_replace('/\033\[(?:\d;?)+m/', '' , "\033[0;36mtext\033[0m");
104-
return preg_replace('/\033\[(?:\d;?)+m/', '', $text);
179+
return preg_replace('/\033\[(?:\d;?)+m/', '', strip_tags($text));
105180
}
106181

182+
/*******************************************************************************
183+
* read/write message
184+
******************************************************************************/
185+
107186
/**
108-
* Returns true if STDOUT supports colorization.
109-
* This code has been copied and adapted from
110-
* \Symfony\Component\Console\Output\OutputStream.
111-
* @return boolean
187+
* @param mixed $message
188+
* @param bool $nl
189+
* @return string
112190
*/
113-
public static function isSupportColor()
191+
public static function read($message = null, $nl = false): string
114192
{
115-
if (DIRECTORY_SEPARATOR === '\\') {
116-
return
117-
'10.0.10586' === PHP_WINDOWS_VERSION_MAJOR . '.' . PHP_WINDOWS_VERSION_MINOR . '.' . PHP_WINDOWS_VERSION_BUILD
118-
|| false !== getenv('ANSICON')
119-
|| 'ON' === getenv('ConEmuANSI')
120-
|| 'xterm' === getenv('TERM')// || 'cygwin' === getenv('TERM')
121-
;
193+
if ($message) {
194+
self::write($message, $nl);
122195
}
123196

124-
if (!defined('STDOUT')) {
125-
return false;
197+
return trim(fgets(STDIN));
198+
}
199+
200+
/**
201+
* write message to console
202+
* @param $message
203+
* @param bool $nl
204+
* @param bool $quit
205+
*/
206+
public static function write($message, $nl = true, $quit = false)
207+
{
208+
if (is_array($message)) {
209+
$message = implode($nl ? PHP_EOL : '', $message);
126210
}
127211

128-
return self::isInteractive(STDOUT);
212+
self::stdout(self::renderColor($message), $nl, $quit);
129213
}
130214

131215
/**
132-
* Returns if the file descriptor is an interactive terminal or not.
133-
* @param int|resource $fileDescriptor
216+
* Logs data to stdout
217+
* @param string $message
218+
* @param bool $nl
219+
* @param bool|int $quit
220+
*/
221+
public static function stdout($message, $nl = true, $quit = false)
222+
{
223+
fwrite(\STDOUT, $message . ($nl ? PHP_EOL : ''));
224+
fflush(\STDOUT);
225+
226+
if (($isTrue = true === $quit) || is_int($quit)) {
227+
$code = $isTrue ? 0 : $quit;
228+
exit($code);
229+
}
230+
}
231+
232+
/**
233+
* Logs data to stderr
234+
* @param string $message
235+
* @param bool $nl
236+
* @param bool|int $quit
237+
*/
238+
public static function stderr($message, $nl = true, $quit = -200)
239+
{
240+
fwrite(\STDERR, self::color('[ERROR] ', 'red') . $message . ($nl ? PHP_EOL : ''));
241+
fflush(\STDOUT);
242+
243+
if (($isTrue = true === $quit) || is_int($quit)) {
244+
$code = $isTrue ? 0 : $quit;
245+
exit($code);
246+
}
247+
}
248+
249+
/**
250+
* Returns true if STDOUT supports colorization.
251+
* This code has been copied and adapted from
252+
* \Symfony\Component\Console\Output\OutputStream.
134253
* @return boolean
135254
*/
136-
public static function isInteractive($fileDescriptor)
255+
public static function isSupportColor()
137256
{
138-
return function_exists('posix_isatty') && @posix_isatty($fileDescriptor);
257+
return EnvHelper::isSupportColor();
139258
}
140259

141260
/**
@@ -152,7 +271,7 @@ public static function isInteractive($fileDescriptor)
152271
* @param bool $mergeOpts
153272
* @return array
154273
*/
155-
public static function parseOptArgs(array $noValues = [], $mergeOpts = false)
274+
public static function argOptParse(array $noValues = [], $mergeOpts = false)
156275
{
157276
$params = $GLOBALS['argv'];
158277
reset($params);
@@ -164,6 +283,8 @@ public static function parseOptArgs(array $noValues = [], $mergeOpts = false)
164283
// each() will deprecated at 7.2 so,there use current and next instead it.
165284
// while (list(,$p) = each($params)) {
166285
while (false !== ($p = current($params))) {
286+
next($params);
287+
167288
// is options
168289
if ($p{0} === '-') {
169290
$isLong = false;
@@ -228,35 +349,4 @@ public static function parseOptArgs(array $noValues = [], $mergeOpts = false)
228349
return [$fullScript, $script, $args, $sOpts, $lOpts];
229350
}
230351

231-
/**
232-
* Logs data to stdout
233-
* @param string $logString
234-
* @param bool $nl
235-
* @param bool|int $quit
236-
*/
237-
public static function stdout($logString, $nl = true, $quit = false)
238-
{
239-
fwrite(\STDOUT, $logString . ($nl ? PHP_EOL : ''));
240-
241-
if (($isTrue = true === $quit) || is_int($quit)) {
242-
$code = $isTrue ? 0 : $quit;
243-
exit($code);
244-
}
245-
}
246-
247-
/**
248-
* Logs data to stderr
249-
* @param string $text
250-
* @param bool $nl
251-
* @param bool|int $quit
252-
*/
253-
public static function stderr($text, $nl = true, $quit = -200)
254-
{
255-
fwrite(\STDERR, self::color('[ERROR] ', 'red') . $text . ($nl ? PHP_EOL : ''));
256-
257-
if (($isTrue = true === $quit) || is_int($quit)) {
258-
$code = $isTrue ? 0 : $quit;
259-
exit($code);
260-
}
261-
}
262352
}

0 commit comments

Comments
 (0)