PluginProbe
Depicter — Popup & Slider Builder / 1.2.0
Depicter — Popup & Slider Builder v1.2.0
4.8.1 trunk 1.0.0 1.1.0 1.1.2 1.1.4 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.5 1.3.8 1.5.0 1.5.1 1.5.2 1.5.5 1.6.0 1.6.1 1.6.2 1.7.0 All 76 releases
depicter / vendor / symfony / console / Style / SymfonyStyle.php

SymfonyStyle.php in Depicter — Popup & Slider Builder 1.2.0, at vendor/symfony/console/Style/SymfonyStyle.php

499 lines 13.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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\InvalidArgumentException;
15 use Symfony\Component\Console\Exception\RuntimeException;
16 use Symfony\Component\Console\Formatter\OutputFormatter;
17 use Symfony\Component\Console\Helper\Helper;
18 use Symfony\Component\Console\Helper\ProgressBar;
19 use Symfony\Component\Console\Helper\SymfonyQuestionHelper;
20 use Symfony\Component\Console\Helper\Table;
21 use Symfony\Component\Console\Helper\TableCell;
22 use Symfony\Component\Console\Helper\TableSeparator;
23 use Symfony\Component\Console\Input\InputInterface;
24 use Symfony\Component\Console\Output\OutputInterface;
25 use Symfony\Component\Console\Output\TrimmedBufferOutput;
26 use Symfony\Component\Console\Question\ChoiceQuestion;
27 use Symfony\Component\Console\Question\ConfirmationQuestion;
28 use Symfony\Component\Console\Question\Question;
29 use Symfony\Component\Console\Terminal;
30
31 /**
32 * Output decorator helpers for the Symfony Style Guide.
33 *
34 * @author Kevin Bond <kevinbond@gmail.com>
35 */
36 class SymfonyStyle extends OutputStyle
37 {
38 public const MAX_LINE_LENGTH = 120;
39
40 private $input;
41 private $questionHelper;
42 private $progressBar;
43 private $lineLength;
44 private $bufferedOutput;
45
46 public function __construct(InputInterface $input, OutputInterface $output)
47 {
48 $this->input = $input;
49 $this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), false, clone $output->getFormatter());
50 // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not.
51 $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH;
52 $this->lineLength = min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH);
53
54 parent::__construct($output);
55 }
56
57 /**
58 * Formats a message as a block of text.
59 *
60 * @param string|array $messages The message to write in the block
61 */
62 public function block($messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = true)
63 {
64 $messages = \is_array($messages) ? array_values($messages) : [$messages];
65
66 $this->autoPrependBlock();
67 $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape));
68 $this->newLine();
69 }
70
71 /**
72 * {@inheritdoc}
73 */
74 public function title(string $message)
75 {
76 $this->autoPrependBlock();
77 $this->writeln([
78 sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
79 sprintf('<comment>%s</>', str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
80 ]);
81 $this->newLine();
82 }
83
84 /**
85 * {@inheritdoc}
86 */
87 public function section(string $message)
88 {
89 $this->autoPrependBlock();
90 $this->writeln([
91 sprintf('<comment>%s</>', OutputFormatter::escapeTrailingBackslash($message)),
92 sprintf('<comment>%s</>', str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message))),
93 ]);
94 $this->newLine();
95 }
96
97 /**
98 * {@inheritdoc}
99 */
100 public function listing(array $elements)
101 {
102 $this->autoPrependText();
103 $elements = array_map(function ($element) {
104 return sprintf(' * %s', $element);
105 }, $elements);
106
107 $this->writeln($elements);
108 $this->newLine();
109 }
110
111 /**
112 * {@inheritdoc}
113 */
114 public function text($message)
115 {
116 $this->autoPrependText();
117
118 $messages = \is_array($message) ? array_values($message) : [$message];
119 foreach ($messages as $message) {
120 $this->writeln(sprintf(' %s', $message));
121 }
122 }
123
124 /**
125 * Formats a command comment.
126 *
127 * @param string|array $message
128 */
129 public function comment($message)
130 {
131 $this->block($message, null, null, '<fg=default;bg=default> // </>', false, false);
132 }
133
134 /**
135 * {@inheritdoc}
136 */
137 public function success($message)
138 {
139 $this->block($message, 'OK', 'fg=black;bg=green', ' ', true);
140 }
141
142 /**
143 * {@inheritdoc}
144 */
145 public function error($message)
146 {
147 $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', true);
148 }
149
150 /**
151 * {@inheritdoc}
152 */
153 public function warning($message)
154 {
155 $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', true);
156 }
157
158 /**
159 * {@inheritdoc}
160 */
161 public function note($message)
162 {
163 $this->block($message, 'NOTE', 'fg=yellow', ' ! ');
164 }
165
166 /**
167 * {@inheritdoc}
168 */
169 public function caution($message)
170 {
171 $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', true);
172 }
173
174 /**
175 * {@inheritdoc}
176 */
177 public function table(array $headers, array $rows)
178 {
179 $style = clone Table::getStyleDefinition('symfony-style-guide');
180 $style->setCellHeaderFormat('<info>%s</info>');
181
182 $table = new Table($this);
183 $table->setHeaders($headers);
184 $table->setRows($rows);
185 $table->setStyle($style);
186
187 $table->render();
188 $this->newLine();
189 }
190
191 /**
192 * Formats a horizontal table.
193 */
194 public function horizontalTable(array $headers, array $rows)
195 {
196 $style = clone Table::getStyleDefinition('symfony-style-guide');
197 $style->setCellHeaderFormat('<info>%s</info>');
198
199 $table = new Table($this);
200 $table->setHeaders($headers);
201 $table->setRows($rows);
202 $table->setStyle($style);
203 $table->setHorizontal(true);
204
205 $table->render();
206 $this->newLine();
207 }
208
209 /**
210 * Formats a list of key/value horizontally.
211 *
212 * Each row can be one of:
213 * * 'A title'
214 * * ['key' => 'value']
215 * * new TableSeparator()
216 *
217 * @param string|array|TableSeparator ...$list
218 */
219 public function definitionList(...$list)
220 {
221 $style = clone Table::getStyleDefinition('symfony-style-guide');
222 $style->setCellHeaderFormat('<info>%s</info>');
223
224 $table = new Table($this);
225 $headers = [];
226 $row = [];
227 foreach ($list as $value) {
228 if ($value instanceof TableSeparator) {
229 $headers[] = $value;
230 $row[] = $value;
231 continue;
232 }
233 if (\is_string($value)) {
234 $headers[] = new TableCell($value, ['colspan' => 2]);
235 $row[] = null;
236 continue;
237 }
238 if (!\is_array($value)) {
239 throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.');
240 }
241 $headers[] = key($value);
242 $row[] = current($value);
243 }
244
245 $table->setHeaders($headers);
246 $table->setRows([$row]);
247 $table->setHorizontal();
248 $table->setStyle($style);
249
250 $table->render();
251 $this->newLine();
252 }
253
254 /**
255 * {@inheritdoc}
256 */
257 public function ask(string $question, ?string $default = null, $validator = null)
258 {
259 $question = new Question($question, $default);
260 $question->setValidator($validator);
261
262 return $this->askQuestion($question);
263 }
264
265 /**
266 * {@inheritdoc}
267 */
268 public function askHidden(string $question, $validator = null)
269 {
270 $question = new Question($question);
271
272 $question->setHidden(true);
273 $question->setValidator($validator);
274
275 return $this->askQuestion($question);
276 }
277
278 /**
279 * {@inheritdoc}
280 */
281 public function confirm($question, $default = true)
282 {
283 return $this->askQuestion(new ConfirmationQuestion($question, $default));
284 }
285
286 /**
287 * {@inheritdoc}
288 */
289 public function choice(string $question, array $choices, $default = null)
290 {
291 if (null !== $default) {
292 $values = array_flip($choices);
293 $default = $values[$default] ?? $default;
294 }
295
296 return $this->askQuestion(new ChoiceQuestion($question, $choices, $default));
297 }
298
299 /**
300 * {@inheritdoc}
301 */
302 public function progressStart(int $max = 0)
303 {
304 $this->progressBar = $this->createProgressBar($max);
305 $this->progressBar->start();
306 }
307
308 /**
309 * {@inheritdoc}
310 */
311 public function progressAdvance(int $step = 1)
312 {
313 $this->getProgressBar()->advance($step);
314 }
315
316 /**
317 * {@inheritdoc}
318 */
319 public function progressFinish()
320 {
321 $this->getProgressBar()->finish();
322 $this->newLine(2);
323 $this->progressBar = null;
324 }
325
326 /**
327 * {@inheritdoc}
328 */
329 public function createProgressBar(int $max = 0)
330 {
331 $progressBar = parent::createProgressBar($max);
332
333 if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === getenv('TERM_PROGRAM')) {
334 $progressBar->setEmptyBarCharacter(''); // light shade character \u2591
335 $progressBar->setProgressCharacter('');
336 $progressBar->setBarCharacter(''); // dark shade character \u2593
337 }
338
339 return $progressBar;
340 }
341
342 /**
343 * @return mixed
344 */
345 public function askQuestion(Question $question)
346 {
347 if ($this->input->isInteractive()) {
348 $this->autoPrependBlock();
349 }
350
351 if (!$this->questionHelper) {
352 $this->questionHelper = new SymfonyQuestionHelper();
353 }
354
355 $answer = $this->questionHelper->ask($this->input, $this, $question);
356
357 if ($this->input->isInteractive()) {
358 $this->newLine();
359 $this->bufferedOutput->write("\n");
360 }
361
362 return $answer;
363 }
364
365 /**
366 * {@inheritdoc}
367 */
368 public function writeln($messages, int $type = self::OUTPUT_NORMAL)
369 {
370 if (!is_iterable($messages)) {
371 $messages = [$messages];
372 }
373
374 foreach ($messages as $message) {
375 parent::writeln($message, $type);
376 $this->writeBuffer($message, true, $type);
377 }
378 }
379
380 /**
381 * {@inheritdoc}
382 */
383 public function write($messages, bool $newline = false, int $type = self::OUTPUT_NORMAL)
384 {
385 if (!is_iterable($messages)) {
386 $messages = [$messages];
387 }
388
389 foreach ($messages as $message) {
390 parent::write($message, $newline, $type);
391 $this->writeBuffer($message, $newline, $type);
392 }
393 }
394
395 /**
396 * {@inheritdoc}
397 */
398 public function newLine(int $count = 1)
399 {
400 parent::newLine($count);
401 $this->bufferedOutput->write(str_repeat("\n", $count));
402 }
403
404 /**
405 * Returns a new instance which makes use of stderr if available.
406 *
407 * @return self
408 */
409 public function getErrorStyle()
410 {
411 return new self($this->input, $this->getErrorOutput());
412 }
413
414 private function getProgressBar(): ProgressBar
415 {
416 if (!$this->progressBar) {
417 throw new RuntimeException('The ProgressBar is not started.');
418 }
419
420 return $this->progressBar;
421 }
422
423 private function autoPrependBlock(): void
424 {
425 $chars = substr(str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);
426
427 if (!isset($chars[0])) {
428 $this->newLine(); //empty history, so we should start with a new line.
429
430 return;
431 }
432 //Prepend new line for each non LF chars (This means no blank line was output before)
433 $this->newLine(2 - substr_count($chars, "\n"));
434 }
435
436 private function autoPrependText(): void
437 {
438 $fetched = $this->bufferedOutput->fetch();
439 //Prepend new line if last char isn't EOL:
440 if ("\n" !== substr($fetched, -1)) {
441 $this->newLine();
442 }
443 }
444
445 private function writeBuffer(string $message, bool $newLine, int $type): void
446 {
447 // We need to know if the last chars are PHP_EOL
448 $this->bufferedOutput->write($message, $newLine, $type);
449 }
450
451 private function createBlock(iterable $messages, string $type = null, string $style = null, string $prefix = ' ', bool $padding = false, bool $escape = false): array
452 {
453 $indentLength = 0;
454 $prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix);
455 $lines = [];
456
457 if (null !== $type) {
458 $type = sprintf('[%s] ', $type);
459 $indentLength = \strlen($type);
460 $lineIndentation = str_repeat(' ', $indentLength);
461 }
462
463 // wrap and add newlines for each element
464 foreach ($messages as $key => $message) {
465 if ($escape) {
466 $message = OutputFormatter::escape($message);
467 }
468
469 $lines = array_merge($lines, explode(\PHP_EOL, wordwrap($message, $this->lineLength - $prefixLength - $indentLength, \PHP_EOL, true)));
470
471 if (\count($messages) > 1 && $key < \count($messages) - 1) {
472 $lines[] = '';
473 }
474 }
475
476 $firstLineIndex = 0;
477 if ($padding && $this->isDecorated()) {
478 $firstLineIndex = 1;
479 array_unshift($lines, '');
480 $lines[] = '';
481 }
482
483 foreach ($lines as $i => &$line) {
484 if (null !== $type) {
485 $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line;
486 }
487
488 $line = $prefix.$line;
489 $line .= str_repeat(' ', $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line));
490
491 if ($style) {
492 $line = sprintf('<%s>%s</>', $style, $line);
493 }
494 }
495
496 return $lines;
497 }
498 }
499