More updates to stop using dev or alpha or beta versions.
[yaffs-website] / vendor / jakub-onderka / php-console-color / src / JakubOnderka / PhpConsoleColor / 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             return getenv('ANSICON') !== false || getenv('ConEmuANSI') === 'ON';
205         }
206
207         return function_exists('posix_isatty') && @posix_isatty(STDOUT);
208     }
209
210     /**
211      * @return bool
212      */
213     public function are256ColorsSupported()
214     {
215         return DIRECTORY_SEPARATOR === '/' && strpos(getenv('TERM'), '256color') !== false;
216     }
217
218     /**
219      * @return array
220      */
221     public function getPossibleStyles()
222     {
223         return array_keys($this->styles);
224     }
225
226     /**
227      * @param string $name
228      * @return string
229      * @throws InvalidStyleException
230      */
231     private function themeSequence($name)
232     {
233         $sequences = array();
234         foreach ($this->themes[$name] as $style) {
235             $sequences[] = $this->styleSequence($style);
236         }
237         return $sequences;
238     }
239
240     /**
241      * @param string $style
242      * @return string
243      * @throws InvalidStyleException
244      */
245     private function styleSequence($style)
246     {
247         if (array_key_exists($style, $this->styles)) {
248             return $this->styles[$style];
249         }
250
251         if (!$this->are256ColorsSupported()) {
252             return null;
253         }
254
255         preg_match(self::COLOR256_REGEXP, $style, $matches);
256
257         $type = $matches[1] === 'bg_' ? self::BACKGROUND : self::FOREGROUND;
258         $value = $matches[2];
259
260         return "$type;5;$value";
261     }
262
263     /**
264      * @param string $style
265      * @return bool
266      */
267     private function isValidStyle($style)
268     {
269         return array_key_exists($style, $this->styles) || preg_match(self::COLOR256_REGEXP, $style);
270     }
271
272     /**
273      * @param string|int $value
274      * @return string
275      */
276     private function escSequence($value)
277     {
278         return "\033[{$value}m";
279     }
280 }