20
20
*/
21
21
class OutputFormatter implements OutputFormatterInterface
22
22
{
23
- /**
24
- * The pattern to phrase the format.
25
- */
26
- const FORMAT_PATTERN = '#( \\\\?)<(/?)([a-z][a-z0-9_=;-]*)?>((?: [^< \\\\]+ | (?!<(?:/?[a-z]|/>)). | .(?<= \\\\<) )*)#isx ' ;
27
-
28
23
private $ decorated ;
29
24
private $ styles = array ();
30
25
private $ styleStack ;
@@ -147,9 +142,43 @@ public function getStyle($name)
147
142
*/
148
143
public function format ($ message )
149
144
{
150
- $ message = preg_replace_callback (self ::FORMAT_PATTERN , array ($ this , 'replaceStyle ' ), $ message );
145
+ $ offset = 0 ;
146
+ $ output = '' ;
147
+ $ tagRegex = '[a-z][a-z0-9_=;-]* ' ;
148
+ preg_match_all ("#<(( $ tagRegex) | /( $ tagRegex)?)>#isx " , $ message , $ matches , PREG_OFFSET_CAPTURE );
149
+ foreach ($ matches [0 ] as $ i => $ match ) {
150
+ $ pos = $ match [1 ];
151
+ $ text = $ match [0 ];
152
+
153
+ // add the text up to the next tag
154
+ $ output .= $ this ->applyCurrentStyle (substr ($ message , $ offset , $ pos - $ offset ));
155
+ $ offset = $ pos + strlen ($ text );
156
+
157
+ // opening tag?
158
+ if ($ open = '/ ' != $ text [1 ]) {
159
+ $ tag = $ matches [1 ][$ i ][0 ];
160
+ } else {
161
+ $ tag = isset ($ matches [3 ][$ i ][0 ]) ? $ matches [3 ][$ i ][0 ] : '' ;
162
+ }
163
+
164
+ if (!$ open && !$ tag ) {
165
+ // </>
166
+ $ this ->styleStack ->pop ();
167
+ } elseif ($ pos && '\\' == $ message [$ pos - 1 ]) {
168
+ // escaped tag
169
+ $ output .= $ this ->applyCurrentStyle ($ text );
170
+ } elseif (false === $ style = $ this ->createStyleFromString (strtolower ($ tag ))) {
171
+ $ output .= $ this ->applyCurrentStyle ($ text );
172
+ } elseif ($ open ) {
173
+ $ this ->styleStack ->push ($ style );
174
+ } else {
175
+ $ this ->styleStack ->pop ($ style );
176
+ }
177
+ }
178
+
179
+ $ output .= $ this ->applyCurrentStyle (substr ($ message , $ offset ));
151
180
152
- return str_replace ('\\< ' , '< ' , $ message );
181
+ return str_replace ('\\< ' , '< ' , $ output );
153
182
}
154
183
155
184
/**
@@ -160,53 +189,6 @@ public function getStyleStack()
160
189
return $ this ->styleStack ;
161
190
}
162
191
163
- /**
164
- * Replaces style of the output.
165
- *
166
- * All escaped tags and tags that reference unknown styles are kept as is.
167
- *
168
- * @param array $match
169
- *
170
- * @return string The replaced style
171
- */
172
- private function replaceStyle ($ match )
173
- {
174
- // we got "\<" escaped char
175
- if ('\\' === $ match [1 ]) {
176
- return $ this ->applyCurrentStyle ($ match [0 ]);
177
- }
178
-
179
- if ('' === $ match [3 ]) {
180
- if ('/ ' === $ match [2 ]) {
181
- // we got "</>" tag
182
- $ this ->styleStack ->pop ();
183
-
184
- return $ this ->applyCurrentStyle ($ match [4 ]);
185
- }
186
-
187
- // we got "<>" tag
188
- return '<> ' .$ this ->applyCurrentStyle ($ match [4 ]);
189
- }
190
-
191
- if (isset ($ this ->styles [strtolower ($ match [3 ])])) {
192
- $ style = $ this ->styles [strtolower ($ match [3 ])];
193
- } else {
194
- $ style = $ this ->createStyleFromString ($ match [3 ]);
195
-
196
- if (false === $ style ) {
197
- return $ this ->applyCurrentStyle ($ match [0 ]);
198
- }
199
- }
200
-
201
- if ('/ ' === $ match [2 ]) {
202
- $ this ->styleStack ->pop ($ style );
203
- } else {
204
- $ this ->styleStack ->push ($ style );
205
- }
206
-
207
- return $ this ->applyCurrentStyle ($ match [4 ]);
208
- }
209
-
210
192
/**
211
193
* Tries to create new style instance from string.
212
194
*
@@ -216,6 +198,10 @@ private function replaceStyle($match)
216
198
*/
217
199
private function createStyleFromString ($ string )
218
200
{
201
+ if (isset ($ this ->styles [$ string ])) {
202
+ return $ this ->styles [$ string ];
203
+ }
204
+
219
205
if (!preg_match_all ('/([^=]+)=([^;]+)(;|$)/ ' , strtolower ($ string ), $ matches , PREG_SET_ORDER )) {
220
206
return false ;
221
207
}
0 commit comments