90fd1252865c7797946dc77449095fdd0b73175d
[yaffs-website] / vendor / jakub-onderka / php-console-color / src / ConsoleColor.php
1 <?php
2 namespace JakubOnderka\PhpConsoleColor;
3
4 class ConsoleColor
5 {
6     const FOREGROUND = 38,
7         BACKGROUND = 48;
8
9     const COLOR256_REGEXP = '~^(bg_)?color_([0-9]{1,3})$~';
10
11     const RESET_STYLE = 0;
12
13     /** @var bool */
14     private $isSupported;
15
16     /** @var bool */
17     private $forceStyle = false;
18
19     /** @var array */
20     private $styles = array(
21         'none' => null,
22         'bold' => '1',
23         'dark' => '2',
24         'italic' => '3',
25         'underline' => '4',
26         'blink' => '5',
27         'reverse' => '7',
28         'concealed' => '8',
29
30         'default' => '39',
31         'black' => '30',
32         'red' => '31',
33         'green' => '32',
34         'yellow' => '33',
35         'blue' => '34',
36         'magenta' => '35',
37         'cyan' => '36',
38         'light_gray' => '37',
39
40         'dark_gray' => '90',
41         'light_red' => '91',
42         'light_green' => '92',
43         'light_yellow' => '93',
44         'light_blue' => '94',
45         'light_magenta' => '95',
46         'light_cyan' => '96',
47         'white' => '97',
48
49         'bg_default' => '49',
50         'bg_black' => '40',
51         'bg_red' => '41',
52         'bg_green' => '42',
53         'bg_yellow' => '43',
54         'bg_blue' => '44',
55         'bg_magenta' => '45',
56         'bg_cyan' => '46',
57         'bg_light_gray' => '47',
58
59         'bg_dark_gray' => '100',
60         'bg_light_red' => '101',
61         'bg_light_green' => '102',
62         'bg_light_yellow' => '103',
63         'bg_light_blue' => '104',
64         'bg_light_magenta' => '105',
65         'bg_light_cyan' => '106',
66         'bg_white' => '107',
67     );
68
69     /** @var array */
70     private $themes = array();
71
72     public function __construct()
73     {
74         $this->isSupported = $this->isSupported();
75     }
76
77     /**
78      * @param string|array $style
79      * @param string $text
80      * @return string
81      * @throws InvalidStyleException
82      * @throws \InvalidArgumentException
83      */
84     public function apply($style, $text)
85     {
86         if (!$this->isStyleForced() && !$this->isSupported()) {
87             return $text;
88         }
89
90         if (is_string($style)) {
91             $style = array($style);
92         }
93         if (!is_array($style)) {
94             throw new \InvalidArgumentException("Style must be string or array.");
95         }
96
97         $sequences = array();
98
99         foreach ($style as $s) {
100             if (isset($this->themes[$s])) {
101                 $sequences = array_merge($sequences, $this->themeSequence($s));
102             } else if ($this->isValidStyle($s)) {
103                 $sequences[] = $this->styleSequence($s);
104             } else {
105                 throw new InvalidStyleException($s);
106             }
107         }
108
109         $sequences = array_filter($sequences, function ($val) {
110             return $val !== null;
111         });
112
113         if (empty($sequences)) {
114             return $text;
115         }
116
117         return $this->escSequence(implode(';', $sequences)) . $text . $this->escSequence(self::RESET_STYLE);
118     }
119
120     /**
121      * @param bool $forceStyle
122      */
123     public function setForceStyle($forceStyle)
124     {
125         $this->forceStyle = (bool) $forceStyle;
126     }
127
128     /**
129      * @return bool
130      */
131     public function isStyleForced()
132     {
133         return $this->forceStyle;
134     }
135
136     /**
137      * @param array $themes
138      * @throws InvalidStyleException
139      * @throws \InvalidArgumentException
140      */
141     public function setThemes(array $themes)
142     {
143         $this->themes = array();
144         foreach ($themes as $name => $styles) {
145             $this->addTheme($name, $styles);
146         }
147     }
148
149     /**
150      * @param string $name
151      * @param array|string $styles
152      * @throws \InvalidArgumentException
153      * @throws InvalidStyleException
154      */
155     public function addTheme($name, $styles)
156     {
157         if (is_string($styles)) {
158             $styles = array($styles);
159         }
160         if (!is_array($styles)) {
161             throw new \InvalidArgumentException("Style must be string or array.");
162         }
163
164         foreach ($styles as $style) {
165             if (!$this->isValidStyle($style)) {
166                 throw new InvalidStyleException($style);
167             }
168         }
169
170         $this->themes[$name] = $styles;
171     }
172
173     /**
174      * @return array
175      */
176     public function getThemes()
177     {
178         return $this->themes;
179     }
180
181     /**
182      * @param string $name
183      * @return bool
184      */
185     public function hasTheme($name)
186     {
187         return isset($this->themes[$name]);
188     }
189
190     /**
191      * @param string $name
192      */
193     public function removeTheme($name)
194     {
195         unset($this->themes[$name]);
196     }
197
198     /**
199      * @return bool
200      */
201     public function isSupported()
202     {
203         if (DIRECTORY_SEPARATOR === '\\') {
204             if (function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(STDOUT)) {
205                 return true;
206             } elseif (getenv('ANSICON') !== false || getenv('ConEmuANSI') === 'ON') {
207                 return true;
208             }
209             return false;
210         } else {
211             return function_exists('posix_isatty') && @posix_isatty(STDOUT);
212         }
213     }
214
215     /**
216      * @return bool
217      */
218     public function are256ColorsSupported()
219     {
220         if (DIRECTORY_SEPARATOR === '\\') {
221             return function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(STDOUT);
222         } else {
223             return strpos(getenv('TERM'), '256color') !== false;
224         }
225     }
226
227     /**
228      * @return array
229      */
230     public function getPossibleStyles()
231     {
232         return array_keys($this->styles);
233     }
234
235     /**
236      * @param string $name
237      * @return string[]
238      */
239     private function themeSequence($name)
240     {
241         $sequences = array();
242         foreach ($this->themes[$name] as $style) {
243             $sequences[] = $this->styleSequence($style);
244         }
245         return $sequences;
246     }
247
248     /**
249      * @param string $style
250      * @return string
251      */
252     private function styleSequence($style)
253     {
254         if (array_key_exists($style, $this->styles)) {
255             return $this->styles[$style];
256         }
257
258         if (!$this->are256ColorsSupported()) {
259             return null;
260         }
261
262         preg_match(self::COLOR256_REGEXP, $style, $matches);
263
264         $type = $matches[1] === 'bg_' ? self::BACKGROUND : self::FOREGROUND;
265         $value = $matches[2];
266
267         return "$type;5;$value";
268     }
269
270     /**
271      * @param string $style
272      * @return bool
273      */
274     private function isValidStyle($style)
275     {
276         return array_key_exists($style, $this->styles) || preg_match(self::COLOR256_REGEXP, $style);
277     }
278
279     /**
280      * @param string|int $value
281      * @return string
282      */
283     private function escSequence($value)
284     {
285         return "\033[{$value}m";
286     }
287 }