20
20
*/
21
21
class OutputFormatterStyle implements OutputFormatterStyleInterface
22
22
{
23
- private static $ availableForegroundColors = array (
24
- 'black ' => array ('set ' => 30 , 'unset ' => 39 ),
25
- 'red ' => array ('set ' => 31 , 'unset ' => 39 ),
26
- 'green ' => array ('set ' => 32 , 'unset ' => 39 ),
27
- 'yellow ' => array ('set ' => 33 , 'unset ' => 39 ),
28
- 'blue ' => array ('set ' => 34 , 'unset ' => 39 ),
29
- 'magenta ' => array ('set ' => 35 , 'unset ' => 39 ),
30
- 'cyan ' => array ('set ' => 36 , 'unset ' => 39 ),
31
- 'white ' => array ('set ' => 37 , 'unset ' => 39 ),
32
- 'default ' => array ('set ' => 39 , 'unset ' => 39 ),
23
+ private const FOREGROUND_COLOR_FORMATS = array (
24
+ 'normal ' => '3%d ' ,
25
+ 'bright ' => '9%d ' ,
26
+ 'mode ' => '38;5;%d ' ,
33
27
);
34
- private static $ availableBackgroundColors = array (
35
- 'black ' => array ('set ' => 40 , 'unset ' => 49 ),
36
- 'red ' => array ('set ' => 41 , 'unset ' => 49 ),
37
- 'green ' => array ('set ' => 42 , 'unset ' => 49 ),
38
- 'yellow ' => array ('set ' => 43 , 'unset ' => 49 ),
39
- 'blue ' => array ('set ' => 44 , 'unset ' => 49 ),
40
- 'magenta ' => array ('set ' => 45 , 'unset ' => 49 ),
41
- 'cyan ' => array ('set ' => 46 , 'unset ' => 49 ),
42
- 'white ' => array ('set ' => 47 , 'unset ' => 49 ),
43
- 'default ' => array ('set ' => 49 , 'unset ' => 49 ),
28
+ private const FOREGROUND_COLOR_RANGE = array (0 , 255 );
29
+ private const FOREGROUND_COLOR_UNSET = 39 ;
30
+ private const FOREGROUND_COLOR_NAMES = array (
31
+ 'black ' => 0 ,
32
+ 'red ' => 1 ,
33
+ 'green ' => 2 ,
34
+ 'yellow ' => 3 ,
35
+ 'blue ' => 4 ,
36
+ 'magenta ' => 5 ,
37
+ 'cyan ' => 6 ,
38
+ 'white ' => 7 ,
39
+ 'default ' => 9 ,
44
40
);
45
- private static $ availableOptions = array (
41
+ private const BACKGROUND_COLOR_FORMATS = array (
42
+ 'normal ' => '4%d ' ,
43
+ 'bright ' => '10%d ' ,
44
+ 'mode ' => '48;5;%d ' ,
45
+ );
46
+ private const BACKGROUND_COLOR_RANGE = array (0 , 255 );
47
+ private const BACKGROUND_COLOR_UNSET = 49 ;
48
+ private const BACKGROUND_COLOR_NAMES = array (
49
+ 'black ' => 0 ,
50
+ 'red ' => 1 ,
51
+ 'green ' => 2 ,
52
+ 'yellow ' => 3 ,
53
+ 'blue ' => 4 ,
54
+ 'magenta ' => 5 ,
55
+ 'cyan ' => 6 ,
56
+ 'white ' => 7 ,
57
+ 'default ' => 9 ,
58
+ );
59
+ private const FORMATTING_OPTIONS = array (
46
60
'bold ' => array ('set ' => 1 , 'unset ' => 22 ),
47
61
'underscore ' => array ('set ' => 4 , 'unset ' => 24 ),
48
62
'blink ' => array ('set ' => 5 , 'unset ' => 25 ),
@@ -89,15 +103,11 @@ public function setForeground($color = null)
89
103
return ;
90
104
}
91
105
92
- if (!isset (static ::$ availableForegroundColors [$ color ])) {
93
- throw new InvalidArgumentException (sprintf (
94
- 'Invalid foreground color specified: "%s". Expected one of (%s) ' ,
95
- $ color ,
96
- implode (', ' , array_keys (static ::$ availableForegroundColors ))
97
- ));
106
+ if (null === $ foreground = $ this ->resolveColorInstruction ($ color , 'foreground ' )) {
107
+ throw new InvalidArgumentException ($ this ->createColorSetterExceptionMessage ($ color , 'foreground ' ));
98
108
}
99
109
100
- $ this ->foreground = static :: $ availableForegroundColors [ $ color ] ;
110
+ $ this ->foreground = $ foreground ;
101
111
}
102
112
103
113
/**
@@ -115,15 +125,11 @@ public function setBackground($color = null)
115
125
return ;
116
126
}
117
127
118
- if (!isset (static ::$ availableBackgroundColors [$ color ])) {
119
- throw new InvalidArgumentException (sprintf (
120
- 'Invalid background color specified: "%s". Expected one of (%s) ' ,
121
- $ color ,
122
- implode (', ' , array_keys (static ::$ availableBackgroundColors ))
123
- ));
128
+ if (null === $ background = $ this ->resolveColorInstruction ($ color , 'background ' )) {
129
+ throw new InvalidArgumentException ($ this ->createColorSetterExceptionMessage ($ color , 'background ' ));
124
130
}
125
131
126
- $ this ->background = static :: $ availableBackgroundColors [ $ color ] ;
132
+ $ this ->background = $ background ;
127
133
}
128
134
129
135
/**
@@ -135,16 +141,16 @@ public function setBackground($color = null)
135
141
*/
136
142
public function setOption ($ option )
137
143
{
138
- if (!isset (static :: $ availableOptions [$ option ])) {
144
+ if (!isset (self :: FORMATTING_OPTIONS [$ option ])) {
139
145
throw new InvalidArgumentException (sprintf (
140
146
'Invalid option specified: "%s". Expected one of (%s) ' ,
141
147
$ option ,
142
- implode (', ' , array_keys (static :: $ availableOptions ))
148
+ implode (', ' , array_keys (self :: FORMATTING_OPTIONS ))
143
149
));
144
150
}
145
151
146
- if (!in_array (static :: $ availableOptions [$ option ], $ this ->options )) {
147
- $ this ->options [] = static :: $ availableOptions [$ option ];
152
+ if (!in_array (self :: FORMATTING_OPTIONS [$ option ], $ this ->options )) {
153
+ $ this ->options [] = self :: FORMATTING_OPTIONS [$ option ];
148
154
}
149
155
}
150
156
@@ -157,15 +163,15 @@ public function setOption($option)
157
163
*/
158
164
public function unsetOption ($ option )
159
165
{
160
- if (!isset (static :: $ availableOptions [$ option ])) {
166
+ if (!isset (self :: FORMATTING_OPTIONS [$ option ])) {
161
167
throw new InvalidArgumentException (sprintf (
162
168
'Invalid option specified: "%s". Expected one of (%s) ' ,
163
169
$ option ,
164
- implode (', ' , array_keys (static :: $ availableOptions ))
170
+ implode (', ' , array_keys (self :: FORMATTING_OPTIONS ))
165
171
));
166
172
}
167
173
168
- $ pos = array_search (static :: $ availableOptions [$ option ], $ this ->options );
174
+ $ pos = array_search (self :: FORMATTING_OPTIONS [$ option ], $ this ->options );
169
175
if (false !== $ pos ) {
170
176
unset($ this ->options [$ pos ]);
171
177
}
@@ -216,4 +222,84 @@ public function apply($text)
216
222
217
223
return sprintf ("\033[%sm%s \033[%sm " , implode ('; ' , $ setCodes ), $ text , implode ('; ' , $ unsetCodes ));
218
224
}
225
+
226
+ /**
227
+ * @param string $input
228
+ * @param string $context
229
+ *
230
+ * @return array|null
231
+ */
232
+ private function resolveColorInstruction (string $ input , string $ context ): ?array
233
+ {
234
+ list ($ names , $ range , $ unset , $ formats ) = $ this ->resolveColorAttributes ($ context );
235
+ list ($ type , $ name ) = $ this ->resolveColorInput ($ input , $ names );
236
+
237
+ if (('normal ' === $ type || 'bright ' === $ type ) && isset ($ names [$ name ])) {
238
+ $ color = $ names [$ name ];
239
+ }
240
+
241
+ if ('mode ' === $ type && in_array ($ name , range (...$ range ), true )) {
242
+ $ color = $ name ;
243
+ }
244
+
245
+ return isset ($ color ) ? array ('unset ' => $ unset , 'set ' => sprintf ($ formats [$ type ], $ color )) : null ;
246
+ }
247
+
248
+ /**
249
+ * @param string $color
250
+ * @param string $context
251
+ *
252
+ * @return string
253
+ */
254
+ private function createColorSetterExceptionMessage (string $ color , string $ context ): string
255
+ {
256
+ list ($ names , $ range ) = $ this ->resolveColorAttributes ($ context );
257
+ list ($ colorType , $ colorName ) = $ this ->resolveColorInput ($ color , $ names );
258
+
259
+ return sprintf ('Invalid %s color specified: "%s:%s". Expected "mode:[%d-%d]" or "(normal:|bright:)?(%s)" ' ,
260
+ $ context , $ colorType , $ colorName , $ range [0 ], $ range [1 ], implode (', ' , array_keys ($ names )));
261
+ }
262
+
263
+ /**
264
+ * @param string $context
265
+ *
266
+ * @return array
267
+ */
268
+ private function resolveColorAttributes (string $ context ): array
269
+ {
270
+ if ('foreground ' === $ context ) {
271
+ return array (
272
+ self ::FOREGROUND_COLOR_NAMES ,
273
+ self ::FOREGROUND_COLOR_RANGE ,
274
+ self ::FOREGROUND_COLOR_UNSET ,
275
+ self ::FOREGROUND_COLOR_FORMATS ,
276
+ );
277
+ }
278
+
279
+ return array (
280
+ self ::BACKGROUND_COLOR_NAMES ,
281
+ self ::BACKGROUND_COLOR_RANGE ,
282
+ self ::BACKGROUND_COLOR_UNSET ,
283
+ self ::BACKGROUND_COLOR_FORMATS ,
284
+ );
285
+ }
286
+
287
+ /**
288
+ * @param string $color
289
+ * @param string[] $names
290
+ *
291
+ * @return string[]
292
+ */
293
+ private function resolveColorInput (string $ color , array $ names ): array
294
+ {
295
+ if (1 === preg_match (sprintf ('{^(?<type>normal|bright):(?<name>%s)$} ' , implode ('| ' , array_keys ($ names ))), $ color , $ matched )) {
296
+ return array ($ matched ['type ' ], $ matched ['name ' ]);
297
+ }
298
+
299
+ if (1 === preg_match ('{^(?<type>mode):(?<mode>[0-9]{1,3})$} ' , $ color , $ matched )) {
300
+ return array ($ matched ['type ' ], (int ) $ matched ['mode ' ]);
301
+ }
302
+
303
+ return array ('normal ' , $ color );
304
+ }
219
305
}
0 commit comments