1212use Toolkit \Cli \Color ;
1313use function preg_match_all ;
1414use function preg_replace ;
15+ use function preg_replace_callback ;
1516use function sprintf ;
1617use function str_replace ;
1718use 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 /**
0 commit comments