2015-08-17 17:00:26 -07:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Symfony\Component\Console\Style ;
use Symfony\Component\Console\Application ;
2016-04-20 09:56:34 -07:00
use Symfony\Component\Console\Exception\RuntimeException ;
2015-08-17 17:00:26 -07:00
use Symfony\Component\Console\Formatter\OutputFormatter ;
use Symfony\Component\Console\Helper\Helper ;
use Symfony\Component\Console\Helper\ProgressBar ;
use Symfony\Component\Console\Helper\SymfonyQuestionHelper ;
use Symfony\Component\Console\Helper\Table ;
use Symfony\Component\Console\Input\InputInterface ;
2015-08-27 12:03:05 -07:00
use Symfony\Component\Console\Output\BufferedOutput ;
2015-08-17 17:00:26 -07:00
use Symfony\Component\Console\Output\OutputInterface ;
use Symfony\Component\Console\Question\ChoiceQuestion ;
use Symfony\Component\Console\Question\ConfirmationQuestion ;
use Symfony\Component\Console\Question\Question ;
/**
* Output decorator helpers for the Symfony Style Guide .
*
* @ author Kevin Bond < kevinbond @ gmail . com >
*/
class SymfonyStyle extends OutputStyle
{
const MAX_LINE_LENGTH = 120 ;
private $input ;
private $questionHelper ;
private $progressBar ;
private $lineLength ;
2015-08-27 12:03:05 -07:00
private $bufferedOutput ;
2015-08-17 17:00:26 -07:00
/**
* @ param InputInterface $input
* @ param OutputInterface $output
*/
public function __construct ( InputInterface $input , OutputInterface $output )
{
$this -> input = $input ;
2015-08-27 12:03:05 -07:00
$this -> bufferedOutput = new BufferedOutput ( $output -> getVerbosity (), false , clone $output -> getFormatter ());
// Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not.
$this -> lineLength = min ( $this -> getTerminalWidth () - ( int ) ( DIRECTORY_SEPARATOR === '\\' ), self :: MAX_LINE_LENGTH );
2015-08-17 17:00:26 -07:00
parent :: __construct ( $output );
}
/**
* Formats a message as a block of text .
*
* @ param string | array $messages The message to write in the block
* @ param string | null $type The block type ( added in [] on first line )
* @ param string | null $style The style to apply to the whole block
* @ param string $prefix The prefix for the block
* @ param bool $padding Whether to add vertical padding
*/
public function block ( $messages , $type = null , $style = null , $prefix = ' ' , $padding = false )
{
$messages = is_array ( $messages ) ? array_values ( $messages ) : array ( $messages );
2017-02-02 16:28:38 -08:00
$this -> autoPrependBlock ();
$this -> writeln ( $this -> createBlock ( $messages , $type , $style , $prefix , $padding , true ));
2015-08-27 12:03:05 -07:00
$this -> newLine ();
2015-08-17 17:00:26 -07:00
}
/**
* { @ inheritdoc }
*/
public function title ( $message )
{
2015-08-27 12:03:05 -07:00
$this -> autoPrependBlock ();
$this -> writeln ( array (
2017-02-02 16:28:38 -08:00
sprintf ( '<comment>%s</>' , OutputFormatter :: escapeTrailingBackslash ( $message )),
2016-04-20 09:56:34 -07:00
sprintf ( '<comment>%s</>' , str_repeat ( '=' , Helper :: strlenWithoutDecoration ( $this -> getFormatter (), $message ))),
2015-08-27 12:03:05 -07:00
));
$this -> newLine ();
2015-08-17 17:00:26 -07:00
}
/**
* { @ inheritdoc }
*/
public function section ( $message )
{
2015-08-27 12:03:05 -07:00
$this -> autoPrependBlock ();
$this -> writeln ( array (
2017-02-02 16:28:38 -08:00
sprintf ( '<comment>%s</>' , OutputFormatter :: escapeTrailingBackslash ( $message )),
2016-04-20 09:56:34 -07:00
sprintf ( '<comment>%s</>' , str_repeat ( '-' , Helper :: strlenWithoutDecoration ( $this -> getFormatter (), $message ))),
2015-08-27 12:03:05 -07:00
));
$this -> newLine ();
2015-08-17 17:00:26 -07:00
}
/**
* { @ inheritdoc }
*/
public function listing ( array $elements )
{
2015-08-27 12:03:05 -07:00
$this -> autoPrependText ();
2015-08-17 17:00:26 -07:00
$elements = array_map ( function ( $element ) {
2015-08-27 12:03:05 -07:00
return sprintf ( ' * %s' , $element );
}, $elements );
2015-08-17 17:00:26 -07:00
2015-08-27 12:03:05 -07:00
$this -> writeln ( $elements );
$this -> newLine ();
2015-08-17 17:00:26 -07:00
}
/**
* { @ inheritdoc }
*/
public function text ( $message )
{
2015-08-27 12:03:05 -07:00
$this -> autoPrependText ();
2016-04-20 09:56:34 -07:00
$messages = is_array ( $message ) ? array_values ( $message ) : array ( $message );
foreach ( $messages as $message ) {
$this -> writeln ( sprintf ( ' %s' , $message ));
2015-08-17 17:00:26 -07:00
}
2016-04-20 09:56:34 -07:00
}
/**
2017-02-02 16:28:38 -08:00
* Formats a command comment .
*
* @ param string | array $message
2016-04-20 09:56:34 -07:00
*/
public function comment ( $message )
{
$messages = is_array ( $message ) ? array_values ( $message ) : array ( $message );
2017-02-02 16:28:38 -08:00
$this -> autoPrependBlock ();
$this -> writeln ( $this -> createBlock ( $messages , null , null , '<fg=default;bg=default> // </>' ));
$this -> newLine ();
2015-08-17 17:00:26 -07:00
}
/**
* { @ inheritdoc }
*/
public function success ( $message )
{
2015-11-17 13:42:33 -08:00
$this -> block ( $message , 'OK' , 'fg=black;bg=green' , ' ' , true );
2015-08-17 17:00:26 -07:00
}
/**
* { @ inheritdoc }
*/
public function error ( $message )
{
$this -> block ( $message , 'ERROR' , 'fg=white;bg=red' , ' ' , true );
}
/**
* { @ inheritdoc }
*/
public function warning ( $message )
{
$this -> block ( $message , 'WARNING' , 'fg=white;bg=red' , ' ' , true );
}
/**
* { @ inheritdoc }
*/
public function note ( $message )
{
$this -> block ( $message , 'NOTE' , 'fg=yellow' , ' ! ' );
}
/**
* { @ inheritdoc }
*/
public function caution ( $message )
{
$this -> block ( $message , 'CAUTION' , 'fg=white;bg=red' , ' ! ' , true );
}
/**
* { @ inheritdoc }
*/
public function table ( array $headers , array $rows )
{
2017-02-02 16:28:38 -08:00
$style = clone Table :: getStyleDefinition ( 'symfony-style-guide' );
$style -> setCellHeaderFormat ( '<info>%s</info>' );
2015-08-17 17:00:26 -07:00
$table = new Table ( $this );
$table -> setHeaders ( $headers );
$table -> setRows ( $rows );
2017-02-02 16:28:38 -08:00
$table -> setStyle ( $style );
2015-08-17 17:00:26 -07:00
$table -> render ();
$this -> newLine ();
}
/**
* { @ inheritdoc }
*/
public function ask ( $question , $default = null , $validator = null )
{
$question = new Question ( $question , $default );
$question -> setValidator ( $validator );
2015-08-27 12:03:05 -07:00
return $this -> askQuestion ( $question );
2015-08-17 17:00:26 -07:00
}
/**
* { @ inheritdoc }
*/
public function askHidden ( $question , $validator = null )
{
$question = new Question ( $question );
2015-08-27 12:03:05 -07:00
2015-08-17 17:00:26 -07:00
$question -> setHidden ( true );
2015-08-27 12:03:05 -07:00
$question -> setValidator ( $validator );
2015-08-17 17:00:26 -07:00
2015-08-27 12:03:05 -07:00
return $this -> askQuestion ( $question );
2015-08-17 17:00:26 -07:00
}
/**
* { @ inheritdoc }
*/
public function confirm ( $question , $default = true )
{
return $this -> askQuestion ( new ConfirmationQuestion ( $question , $default ));
}
/**
* { @ inheritdoc }
*/
public function choice ( $question , array $choices , $default = null )
{
if ( null !== $default ) {
$values = array_flip ( $choices );
$default = $values [ $default ];
}
return $this -> askQuestion ( new ChoiceQuestion ( $question , $choices , $default ));
}
/**
* { @ inheritdoc }
*/
public function progressStart ( $max = 0 )
{
$this -> progressBar = $this -> createProgressBar ( $max );
$this -> progressBar -> start ();
}
/**
* { @ inheritdoc }
*/
public function progressAdvance ( $step = 1 )
{
$this -> getProgressBar () -> advance ( $step );
}
/**
* { @ inheritdoc }
*/
public function progressFinish ()
{
$this -> getProgressBar () -> finish ();
$this -> newLine ( 2 );
$this -> progressBar = null ;
}
/**
* { @ inheritdoc }
*/
public function createProgressBar ( $max = 0 )
{
$progressBar = parent :: createProgressBar ( $max );
2016-04-20 09:56:34 -07:00
if ( '\\' !== DIRECTORY_SEPARATOR ) {
2015-08-17 17:00:26 -07:00
$progressBar -> setEmptyBarCharacter ( '░' ); // light shade character \u2591
$progressBar -> setProgressCharacter ( '' );
$progressBar -> setBarCharacter ( '▓' ); // dark shade character \u2593
}
return $progressBar ;
}
/**
* @ param Question $question
*
* @ return string
*/
public function askQuestion ( Question $question )
{
2015-08-27 12:03:05 -07:00
if ( $this -> input -> isInteractive ()) {
$this -> autoPrependBlock ();
}
2015-08-17 17:00:26 -07:00
if ( ! $this -> questionHelper ) {
$this -> questionHelper = new SymfonyQuestionHelper ();
}
$answer = $this -> questionHelper -> ask ( $this -> input , $this , $question );
2015-08-27 12:03:05 -07:00
if ( $this -> input -> isInteractive ()) {
$this -> newLine ();
$this -> bufferedOutput -> write ( " \n " );
}
2015-08-17 17:00:26 -07:00
return $answer ;
}
2015-08-27 12:03:05 -07:00
/**
* { @ inheritdoc }
*/
public function writeln ( $messages , $type = self :: OUTPUT_NORMAL )
{
parent :: writeln ( $messages , $type );
$this -> bufferedOutput -> writeln ( $this -> reduceBuffer ( $messages ), $type );
}
/**
* { @ inheritdoc }
*/
public function write ( $messages , $newline = false , $type = self :: OUTPUT_NORMAL )
{
parent :: write ( $messages , $newline , $type );
$this -> bufferedOutput -> write ( $this -> reduceBuffer ( $messages ), $newline , $type );
}
/**
* { @ inheritdoc }
*/
public function newLine ( $count = 1 )
{
parent :: newLine ( $count );
$this -> bufferedOutput -> write ( str_repeat ( " \n " , $count ));
}
2015-08-17 17:00:26 -07:00
/**
* @ return ProgressBar
*/
private function getProgressBar ()
{
if ( ! $this -> progressBar ) {
2016-04-20 09:56:34 -07:00
throw new RuntimeException ( 'The ProgressBar is not started.' );
2015-08-17 17:00:26 -07:00
}
return $this -> progressBar ;
}
private function getTerminalWidth ()
{
$application = new Application ();
$dimensions = $application -> getTerminalDimensions ();
return $dimensions [ 0 ] ? : self :: MAX_LINE_LENGTH ;
}
2015-08-27 12:03:05 -07:00
private function autoPrependBlock ()
{
$chars = substr ( str_replace ( PHP_EOL , " \n " , $this -> bufferedOutput -> fetch ()), - 2 );
2015-09-04 13:20:09 -07:00
if ( ! isset ( $chars [ 0 ])) {
2015-08-27 12:03:05 -07:00
return $this -> newLine (); //empty history, so we should start with a new line.
}
//Prepend new line for each non LF chars (This means no blank line was output before)
$this -> newLine ( 2 - substr_count ( $chars , " \n " ));
}
private function autoPrependText ()
{
$fetched = $this -> bufferedOutput -> fetch ();
//Prepend new line if last char isn't EOL:
if ( " \n " !== substr ( $fetched , - 1 )) {
$this -> newLine ();
}
}
private function reduceBuffer ( $messages )
{
// We need to know if the two last chars are PHP_EOL
// Preserve the last 4 chars inserted (PHP_EOL on windows is two chars) in the history buffer
return array_map ( function ( $value ) {
return substr ( $value , - 4 );
}, array_merge ( array ( $this -> bufferedOutput -> fetch ()), ( array ) $messages ));
}
2017-02-02 16:28:38 -08:00
private function createBlock ( $messages , $type = null , $style = null , $prefix = ' ' , $padding = false , $escape = false )
{
$indentLength = 0 ;
$prefixLength = Helper :: strlenWithoutDecoration ( $this -> getFormatter (), $prefix );
$lines = array ();
if ( null !== $type ) {
$type = sprintf ( '[%s] ' , $type );
$indentLength = strlen ( $type );
$lineIndentation = str_repeat ( ' ' , $indentLength );
}
// wrap and add newlines for each element
foreach ( $messages as $key => $message ) {
if ( $escape ) {
$message = OutputFormatter :: escape ( $message );
}
$lines = array_merge ( $lines , explode ( PHP_EOL , wordwrap ( $message , $this -> lineLength - $prefixLength - $indentLength , PHP_EOL , true )));
if ( count ( $messages ) > 1 && $key < count ( $messages ) - 1 ) {
$lines [] = '' ;
}
}
$firstLineIndex = 0 ;
if ( $padding && $this -> isDecorated ()) {
$firstLineIndex = 1 ;
array_unshift ( $lines , '' );
$lines [] = '' ;
}
foreach ( $lines as $i => & $line ) {
if ( null !== $type ) {
$line = $firstLineIndex === $i ? $type . $line : $lineIndentation . $line ;
}
$line = $prefix . $line ;
$line .= str_repeat ( ' ' , $this -> lineLength - Helper :: strlenWithoutDecoration ( $this -> getFormatter (), $line ));
if ( $style ) {
$line = sprintf ( '<%s>%s</>' , $style , $line );
}
}
return $lines ;
}
2015-08-17 17:00:26 -07:00
}