Mercurial > hg > isophonics-drupal-site
comparison vendor/symfony/console/Style/SymfonyStyle.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 1fec387a4317 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 /* | |
4 * This file is part of the Symfony package. | |
5 * | |
6 * (c) Fabien Potencier <fabien@symfony.com> | |
7 * | |
8 * For the full copyright and license information, please view the LICENSE | |
9 * file that was distributed with this source code. | |
10 */ | |
11 | |
12 namespace Symfony\Component\Console\Style; | |
13 | |
14 use Symfony\Component\Console\Exception\RuntimeException; | |
15 use Symfony\Component\Console\Formatter\OutputFormatter; | |
16 use Symfony\Component\Console\Helper\Helper; | |
17 use Symfony\Component\Console\Helper\ProgressBar; | |
18 use Symfony\Component\Console\Helper\SymfonyQuestionHelper; | |
19 use Symfony\Component\Console\Helper\Table; | |
20 use Symfony\Component\Console\Input\InputInterface; | |
21 use Symfony\Component\Console\Output\BufferedOutput; | |
22 use Symfony\Component\Console\Output\OutputInterface; | |
23 use Symfony\Component\Console\Question\ChoiceQuestion; | |
24 use Symfony\Component\Console\Question\ConfirmationQuestion; | |
25 use Symfony\Component\Console\Question\Question; | |
26 use Symfony\Component\Console\Terminal; | |
27 | |
28 /** | |
29 * Output decorator helpers for the Symfony Style Guide. | |
30 * | |
31 * @author Kevin Bond <kevinbond@gmail.com> | |
32 */ | |
33 class SymfonyStyle extends OutputStyle | |
34 { | |
35 const MAX_LINE_LENGTH = 120; | |
36 | |
37 private $input; | |
38 private $questionHelper; | |
39 private $progressBar; | |
40 private $lineLength; | |
41 private $bufferedOutput; | |
42 | |
43 /** | |
44 * @param InputInterface $input | |
45 * @param OutputInterface $output | |
46 */ | |
47 public function __construct(InputInterface $input, OutputInterface $output) | |
48 { | |
49 $this->input = $input; | |
50 $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter()); | |
51 // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. | |
52 $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH; | |
53 $this->lineLength = min($width - (int) (DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH); | |
54 | |
55 parent::__construct($output); | |
56 } | |
57 | |
58 /** | |
59 * Formats a message as a block of text. | |
60 * | |
61 * @param string|array $messages The message to write in the block | |
62 * @param string|null $type The block type (added in [] on first line) | |
63 * @param string|null $style The style to apply to the whole block | |
64 * @param string $prefix The prefix for the block | |
65 * @param bool $padding Whether to add vertical padding | |
66 */ | |
67 public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false) | |
68 { | |
69 $messages = is_array($messages) ? array_values($messages) : array($messages); | |
70 | |
71 $this->autoPrependBlock(); | |
72 $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, true)); | |
73 $this->newLine(); | |
74 } | |
75 | |
76 /** | |
77 * {@inheritdoc} | |
78 */ | |
79 public function title($message) | |
80 { | |
81 $this->autoPrependBlock(); | |
82 $this->writeln(array( | |
83 sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)), | |
84 sprintf('<comment>%s</>', str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message))), | |
85 )); | |
86 $this->newLine(); | |
87 } | |
88 | |
89 /** | |
90 * {@inheritdoc} | |
91 */ | |
92 public function section($message) | |
93 { | |
94 $this->autoPrependBlock(); | |
95 $this->writeln(array( | |
96 sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)), | |
97 sprintf('<comment>%s</>', str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message))), | |
98 )); | |
99 $this->newLine(); | |
100 } | |
101 | |
102 /** | |
103 * {@inheritdoc} | |
104 */ | |
105 public function listing(array $elements) | |
106 { | |
107 $this->autoPrependText(); | |
108 $elements = array_map(function ($element) { | |
109 return sprintf(' * %s', $element); | |
110 }, $elements); | |
111 | |
112 $this->writeln($elements); | |
113 $this->newLine(); | |
114 } | |
115 | |
116 /** | |
117 * {@inheritdoc} | |
118 */ | |
119 public function text($message) | |
120 { | |
121 $this->autoPrependText(); | |
122 | |
123 $messages = is_array($message) ? array_values($message) : array($message); | |
124 foreach ($messages as $message) { | |
125 $this->writeln(sprintf(' %s', $message)); | |
126 } | |
127 } | |
128 | |
129 /** | |
130 * Formats a command comment. | |
131 * | |
132 * @param string|array $message | |
133 */ | |
134 public function comment($message) | |
135 { | |
136 $messages = is_array($message) ? array_values($message) : array($message); | |
137 | |
138 $this->autoPrependBlock(); | |
139 $this->writeln($this->createBlock($messages, null, null, '<fg=default;bg=default> // </>')); | |
140 $this->newLine(); | |
141 } | |
142 | |
143 /** | |
144 * {@inheritdoc} | |
145 */ | |
146 public function success($message) | |
147 { | |
148 $this->block($message, 'OK', 'fg=black;bg=green', ' ', true); | |
149 } | |
150 | |
151 /** | |
152 * {@inheritdoc} | |
153 */ | |
154 public function error($message) | |
155 { | |
156 $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true); | |
157 } | |
158 | |
159 /** | |
160 * {@inheritdoc} | |
161 */ | |
162 public function warning($message) | |
163 { | |
164 $this->block($message, 'WARNING', 'fg=white;bg=red', ' ', true); | |
165 } | |
166 | |
167 /** | |
168 * {@inheritdoc} | |
169 */ | |
170 public function note($message) | |
171 { | |
172 $this->block($message, 'NOTE', 'fg=yellow', ' ! '); | |
173 } | |
174 | |
175 /** | |
176 * {@inheritdoc} | |
177 */ | |
178 public function caution($message) | |
179 { | |
180 $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true); | |
181 } | |
182 | |
183 /** | |
184 * {@inheritdoc} | |
185 */ | |
186 public function table(array $headers, array $rows) | |
187 { | |
188 $style = clone Table::getStyleDefinition('symfony-style-guide'); | |
189 $style->setCellHeaderFormat('<info>%s</info>'); | |
190 | |
191 $table = new Table($this); | |
192 $table->setHeaders($headers); | |
193 $table->setRows($rows); | |
194 $table->setStyle($style); | |
195 | |
196 $table->render(); | |
197 $this->newLine(); | |
198 } | |
199 | |
200 /** | |
201 * {@inheritdoc} | |
202 */ | |
203 public function ask($question, $default = null, $validator = null) | |
204 { | |
205 $question = new Question($question, $default); | |
206 $question->setValidator($validator); | |
207 | |
208 return $this->askQuestion($question); | |
209 } | |
210 | |
211 /** | |
212 * {@inheritdoc} | |
213 */ | |
214 public function askHidden($question, $validator = null) | |
215 { | |
216 $question = new Question($question); | |
217 | |
218 $question->setHidden(true); | |
219 $question->setValidator($validator); | |
220 | |
221 return $this->askQuestion($question); | |
222 } | |
223 | |
224 /** | |
225 * {@inheritdoc} | |
226 */ | |
227 public function confirm($question, $default = true) | |
228 { | |
229 return $this->askQuestion(new ConfirmationQuestion($question, $default)); | |
230 } | |
231 | |
232 /** | |
233 * {@inheritdoc} | |
234 */ | |
235 public function choice($question, array $choices, $default = null) | |
236 { | |
237 if (null !== $default) { | |
238 $values = array_flip($choices); | |
239 $default = $values[$default]; | |
240 } | |
241 | |
242 return $this->askQuestion(new ChoiceQuestion($question, $choices, $default)); | |
243 } | |
244 | |
245 /** | |
246 * {@inheritdoc} | |
247 */ | |
248 public function progressStart($max = 0) | |
249 { | |
250 $this->progressBar = $this->createProgressBar($max); | |
251 $this->progressBar->start(); | |
252 } | |
253 | |
254 /** | |
255 * {@inheritdoc} | |
256 */ | |
257 public function progressAdvance($step = 1) | |
258 { | |
259 $this->getProgressBar()->advance($step); | |
260 } | |
261 | |
262 /** | |
263 * {@inheritdoc} | |
264 */ | |
265 public function progressFinish() | |
266 { | |
267 $this->getProgressBar()->finish(); | |
268 $this->newLine(2); | |
269 $this->progressBar = null; | |
270 } | |
271 | |
272 /** | |
273 * {@inheritdoc} | |
274 */ | |
275 public function createProgressBar($max = 0) | |
276 { | |
277 $progressBar = parent::createProgressBar($max); | |
278 | |
279 if ('\\' !== DIRECTORY_SEPARATOR) { | |
280 $progressBar->setEmptyBarCharacter('░'); // light shade character \u2591 | |
281 $progressBar->setProgressCharacter(''); | |
282 $progressBar->setBarCharacter('▓'); // dark shade character \u2593 | |
283 } | |
284 | |
285 return $progressBar; | |
286 } | |
287 | |
288 /** | |
289 * @param Question $question | |
290 * | |
291 * @return string | |
292 */ | |
293 public function askQuestion(Question $question) | |
294 { | |
295 if ($this->input->isInteractive()) { | |
296 $this->autoPrependBlock(); | |
297 } | |
298 | |
299 if (!$this->questionHelper) { | |
300 $this->questionHelper = new SymfonyQuestionHelper(); | |
301 } | |
302 | |
303 $answer = $this->questionHelper->ask($this->input, $this, $question); | |
304 | |
305 if ($this->input->isInteractive()) { | |
306 $this->newLine(); | |
307 $this->bufferedOutput->write("\n"); | |
308 } | |
309 | |
310 return $answer; | |
311 } | |
312 | |
313 /** | |
314 * {@inheritdoc} | |
315 */ | |
316 public function writeln($messages, $type = self::OUTPUT_NORMAL) | |
317 { | |
318 parent::writeln($messages, $type); | |
319 $this->bufferedOutput->writeln($this->reduceBuffer($messages), $type); | |
320 } | |
321 | |
322 /** | |
323 * {@inheritdoc} | |
324 */ | |
325 public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL) | |
326 { | |
327 parent::write($messages, $newline, $type); | |
328 $this->bufferedOutput->write($this->reduceBuffer($messages), $newline, $type); | |
329 } | |
330 | |
331 /** | |
332 * {@inheritdoc} | |
333 */ | |
334 public function newLine($count = 1) | |
335 { | |
336 parent::newLine($count); | |
337 $this->bufferedOutput->write(str_repeat("\n", $count)); | |
338 } | |
339 | |
340 /** | |
341 * @return ProgressBar | |
342 */ | |
343 private function getProgressBar() | |
344 { | |
345 if (!$this->progressBar) { | |
346 throw new RuntimeException('The ProgressBar is not started.'); | |
347 } | |
348 | |
349 return $this->progressBar; | |
350 } | |
351 | |
352 private function autoPrependBlock() | |
353 { | |
354 $chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2); | |
355 | |
356 if (!isset($chars[0])) { | |
357 return $this->newLine(); //empty history, so we should start with a new line. | |
358 } | |
359 //Prepend new line for each non LF chars (This means no blank line was output before) | |
360 $this->newLine(2 - substr_count($chars, "\n")); | |
361 } | |
362 | |
363 private function autoPrependText() | |
364 { | |
365 $fetched = $this->bufferedOutput->fetch(); | |
366 //Prepend new line if last char isn't EOL: | |
367 if ("\n" !== substr($fetched, -1)) { | |
368 $this->newLine(); | |
369 } | |
370 } | |
371 | |
372 private function reduceBuffer($messages) | |
373 { | |
374 // We need to know if the two last chars are PHP_EOL | |
375 // Preserve the last 4 chars inserted (PHP_EOL on windows is two chars) in the history buffer | |
376 return array_map(function ($value) { | |
377 return substr($value, -4); | |
378 }, array_merge(array($this->bufferedOutput->fetch()), (array) $messages)); | |
379 } | |
380 | |
381 private function createBlock($messages, $type = null, $style = null, $prefix = ' ', $padding = false, $escape = false) | |
382 { | |
383 $indentLength = 0; | |
384 $prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix); | |
385 $lines = array(); | |
386 | |
387 if (null !== $type) { | |
388 $type = sprintf('[%s] ', $type); | |
389 $indentLength = strlen($type); | |
390 $lineIndentation = str_repeat(' ', $indentLength); | |
391 } | |
392 | |
393 // wrap and add newlines for each element | |
394 foreach ($messages as $key => $message) { | |
395 if ($escape) { | |
396 $message = OutputFormatter::escape($message); | |
397 } | |
398 | |
399 $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - $prefixLength - $indentLength, PHP_EOL, true))); | |
400 | |
401 if (count($messages) > 1 && $key < count($messages) - 1) { | |
402 $lines[] = ''; | |
403 } | |
404 } | |
405 | |
406 $firstLineIndex = 0; | |
407 if ($padding && $this->isDecorated()) { | |
408 $firstLineIndex = 1; | |
409 array_unshift($lines, ''); | |
410 $lines[] = ''; | |
411 } | |
412 | |
413 foreach ($lines as $i => &$line) { | |
414 if (null !== $type) { | |
415 $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line; | |
416 } | |
417 | |
418 $line = $prefix.$line; | |
419 $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line)); | |
420 | |
421 if ($style) { | |
422 $line = sprintf('<%s>%s</>', $style, $line); | |
423 } | |
424 } | |
425 | |
426 return $lines; | |
427 } | |
428 } |