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