Skip to content

Commit 5fe0897

Browse files
committed
feat: support parse nested color tags
1 parent efbe77b commit 5fe0897

File tree

4 files changed

+60
-19
lines changed

4 files changed

+60
-19
lines changed
File renamed without changes.

src/Color.php

+6-4
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,11 @@ class Color extends ANSICode
141141
// option
142142
'b' => '0;1',
143143
'bold' => '0;1',
144-
'fuzzy' => '2',
144+
'fuzzy' => '0;2',
145145
'i' => '0;3',
146146
'italic' => '0;3',
147-
'underscore' => '4',
147+
'us' => '0;4',
148+
'underscore' => '0;4',
148149
'blink' => '5',
149150
'reverse' => '7',
150151
'concealed' => '8',
@@ -292,12 +293,13 @@ public static function render(string $text, $style = null): string
292293
* parse color tag e.g: <info>message</info>
293294
*
294295
* @param string $text
296+
* @param bool $recursive
295297
*
296298
* @return string
297299
*/
298-
public static function parseTag(string $text): string
300+
public static function parseTag(string $text, bool $recursive = false): string
299301
{
300-
return ColorTag::parse($text);
302+
return ColorTag::parse($text, $recursive);
301303
}
302304

303305
/**

src/Color/ColorTag.php

+34-15
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Toolkit\Cli\Color;
1313
use function preg_match_all;
1414
use function preg_replace;
15+
use function preg_replace_callback;
1516
use function sprintf;
1617
use function str_replace;
1718
use function strpos;
@@ -27,7 +28,7 @@ class ColorTag
2728
public const STRIP_TAG = '/<[\/]?[a-zA-Z0-9=;]+>/';
2829

2930
// Regex to match tags/
30-
public const MATCH_TAG = '/<([a-zA-Z0-9=;_]+)>(.*?)<\/\\1>/s';
31+
public const MATCH_TAG = '/<([a-zA-Z0-9=;_]+)>(.*)<\/\\1>/s';
3132

3233
// color
3334
public const BLACK = 'black';
@@ -109,10 +110,11 @@ public static function matchAll(string $text): array
109110

110111
/**
111112
* @param string $text
113+
* @param bool $recursive parse nested tags
112114
*
113115
* @return string
114116
*/
115-
public static function parse(string $text): string
117+
public static function parse(string $text, bool $recursive = false): string
116118
{
117119
if (!$text || false === strpos($text, '</')) {
118120
return $text;
@@ -123,24 +125,41 @@ public static function parse(string $text): string
123125
return self::strip($text);
124126
}
125127

126-
// match color tags
127-
if (!$matches = self::matchAll($text)) {
128-
return $text;
129-
}
128+
return self::pregReplaceTags($text, $recursive);
129+
}
130130

131-
foreach ((array)$matches[0] as $i => $m) {
132-
$key = $matches[1][$i];
131+
/**
132+
* @param string $text
133+
* @param bool $recursive
134+
*
135+
* @return string
136+
*/
137+
public static function pregReplaceTags(string $text, bool $recursive = false): string
138+
{
139+
return preg_replace_callback(self::MATCH_TAG, static function (array $match) use ($recursive) {
140+
$colorCode = '';
141+
$tagName = $match[1];
142+
143+
if (isset(Color::STYLES[$tagName])) {
144+
$colorCode = Color::STYLES[$tagName];
145+
} elseif (strpos($tagName, '=')) {
146+
$colorCode = Color::stringToCode($tagName);
147+
}
133148

134-
if (isset(Color::STYLES[$key])) {
135-
$text = self::replaceColor($text, $key, $matches[2][$i], Color::STYLES[$key]);
149+
// enhance: support parse nested tags
150+
$body = $match[2];
151+
if ($recursive && false !== strpos($body, '</')) {
152+
$body = self::pregReplaceTags($body, $recursive);
153+
}
136154

137-
/** Custom style format @see Color::stringToCode() */
138-
} elseif (strpos($key, '=')) {
139-
$text = self::replaceColor($text, $key, $matches[2][$i], Color::stringToCode($key));
155+
// wrap body with color codes
156+
if ($colorCode) {
157+
return sprintf("\033[%sm%s\033[0m", $colorCode, $body);
140158
}
141-
}
142159

143-
return $text;
160+
// return raw contents.
161+
return $match[0];
162+
}, $text);
144163
}
145164

146165
/**

test/ColorTagTest.php

+20
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
use PHPUnit\Framework\TestCase;
1313
use Toolkit\Cli\Color;
1414
use Toolkit\Cli\ColorTag;
15+
use function vdump;
16+
use const PHP_EOL;
1517

1618
/**
1719
* Class ColorTagTest
@@ -80,8 +82,26 @@ public function testParse(): void
8082
Color::setForceColor(true);
8183

8284
$text = ColorTag::parse('<info>INFO</info>');
85+
echo $text, PHP_EOL;
8386
$this->assertSame("\033[0;32mINFO\033[0m", $text);
8487

88+
// nested Tags
89+
$text = ColorTag::parse('<info>INFO <cyan>CYAN</cyan></info>');
90+
echo $text, PHP_EOL;
91+
$this->assertSame("\033[0;32mINFO <cyan>CYAN</cyan>\033[0m", $text);
92+
93+
Color::resetConfig();
94+
}
95+
96+
public function testParseNestTag(): void
97+
{
98+
Color::setForceColor(true);
99+
100+
// nested Tags
101+
$text = ColorTag::parse('<info>INFO <cyan>CYAN mess</cyan>age</info>', true);
102+
echo $text, PHP_EOL;
103+
$this->assertSame("\033[0;32mINFO \033[0;36mCYAN mess\033[0mage\033[0m", $text);
104+
85105
Color::resetConfig();
86106
}
87107
}

0 commit comments

Comments
 (0)