Skip to content

Commit

Permalink
[Console] ProgressBar - adjust to the window width (static)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba authored and fabpot committed Jun 17, 2016
1 parent 7ccfdb4 commit b030c24
Show file tree
Hide file tree
Showing 5 changed files with 307 additions and 143 deletions.
103 changes: 15 additions & 88 deletions src/Symfony/Component/Console/Application.php
Expand Up @@ -36,6 +36,7 @@
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\Exception\CommandNotFoundException;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Terminal\TerminalDimensionsProvider;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**
Expand Down Expand Up @@ -65,20 +66,24 @@ class Application
private $definition;
private $helperSet;
private $dispatcher;
private $terminalDimensions;
private $defaultCommand;
private $singleCommand;

/**
* Constructor.
*
* @param string $name The name of the application
* @param string $version The version of the application
* @var TerminalDimensionsProvider
*/
public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
private $terminalDimensionsProvider;

/**
* @param string $name The name of the application
* @param string $version The version of the application
* @param TerminalDimensionsProvider $terminalDimensionsProvider
*/
public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN', TerminalDimensionsProvider $terminalDimensionsProvider = null)
{
$this->name = $name;
$this->version = $version;
$this->terminalDimensionsProvider = $terminalDimensionsProvider ?: new TerminalDimensionsProvider();
$this->defaultCommand = 'list';
$this->helperSet = $this->getDefaultHelperSet();
$this->definition = $this->getDefaultInputDefinition();
Expand Down Expand Up @@ -692,9 +697,7 @@ public function renderException(\Exception $e, OutputInterface $output)
*/
protected function getTerminalWidth()
{
$dimensions = $this->getTerminalDimensions();

return $dimensions[0];
return $this->terminalDimensionsProvider->getTerminalWidth();
}

/**
Expand All @@ -704,9 +707,7 @@ protected function getTerminalWidth()
*/
protected function getTerminalHeight()
{
$dimensions = $this->getTerminalDimensions();

return $dimensions[1];
return $this->terminalDimensionsProvider->getTerminalWidth();
}

/**
Expand All @@ -716,33 +717,7 @@ protected function getTerminalHeight()
*/
public function getTerminalDimensions()
{
if ($this->terminalDimensions) {
return $this->terminalDimensions;
}

if ('\\' === DIRECTORY_SEPARATOR) {
// extract [w, H] from "wxh (WxH)"
if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) {
return array((int) $matches[1], (int) $matches[2]);
}
// extract [w, h] from "wxh"
if (preg_match('/^(\d+)x(\d+)$/', $this->getConsoleMode(), $matches)) {
return array((int) $matches[1], (int) $matches[2]);
}
}

if ($sttyString = $this->getSttyColumns()) {
// extract [w, h] from "rows h; columns w;"
if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
return array((int) $matches[2], (int) $matches[1]);
}
// extract [w, h] from "; h rows; w columns"
if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
return array((int) $matches[2], (int) $matches[1]);
}
}

return array(null, null);
return $this->terminalDimensionsProvider->getTerminalDimensions();
}

/**
Expand All @@ -757,7 +732,7 @@ public function getTerminalDimensions()
*/
public function setTerminalDimensions($width, $height)
{
$this->terminalDimensions = array($width, $height);
$this->terminalDimensionsProvider->setTerminalDimensions($width, $height);

return $this;
}
Expand Down Expand Up @@ -927,54 +902,6 @@ protected function getDefaultHelperSet()
));
}

/**
* Runs and parses stty -a if it's available, suppressing any error output.
*
* @return string
*/
private function getSttyColumns()
{
if (!function_exists('proc_open')) {
return;
}

$descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
$process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
if (is_resource($process)) {
$info = stream_get_contents($pipes[1]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);

return $info;
}
}

/**
* Runs and parses mode CON if it's available, suppressing any error output.
*
* @return string <width>x<height> or null if it could not be parsed
*/
private function getConsoleMode()
{
if (!function_exists('proc_open')) {
return;
}

$descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
$process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
if (is_resource($process)) {
$info = stream_get_contents($pipes[1]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);

if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
return $matches[2].'x'.$matches[1];
}
}
}

/**
* Returns abbreviated suggestions in string format.
*
Expand Down
77 changes: 56 additions & 21 deletions src/Symfony/Component/Console/Helper/ProgressBar.php
Expand Up @@ -14,6 +14,7 @@
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Exception\LogicException;
use Symfony\Component\Console\Terminal\TerminalDimensionsProvider;

/**
* The ProgressBar provides helpers to display progress output.
Expand Down Expand Up @@ -49,19 +50,24 @@ class ProgressBar
private static $formats;

/**
* Constructor.
*
* @param OutputInterface $output An OutputInterface instance
* @param int $max Maximum steps (0 if unknown)
* @var TerminalDimensionsProvider
*/
private $terminalDimensionsProvider;

/**
* @param OutputInterface $output An OutputInterface instance
* @param int $max Maximum steps (0 if unknown)
* @param TerminalDimensionsProvider $terminalDimensionsProvider
*/
public function __construct(OutputInterface $output, $max = 0)
public function __construct(OutputInterface $output, $max = 0, TerminalDimensionsProvider $terminalDimensionsProvider = null)
{
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}

$this->output = $output;
$this->setMaxSteps($max);
$this->terminalDimensionsProvider = $terminalDimensionsProvider ?: new TerminalDimensionsProvider();

if (!$this->output->isDecorated()) {
// disable overwrite when output does not support ANSI codes.
Expand Down Expand Up @@ -217,7 +223,7 @@ public function getProgressPercent()
*/
public function setBarWidth($size)
{
$this->barWidth = (int) $size;
$this->barWidth = max(1, (int) $size);
}

/**
Expand Down Expand Up @@ -412,21 +418,9 @@ public function display()
$this->setRealFormat($this->internalFormat ?: $this->determineBestFormat());
}

$this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) {
if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) {
$text = call_user_func($formatter, $this, $this->output);
} elseif (isset($this->messages[$matches[1]])) {
$text = $this->messages[$matches[1]];
} else {
return $matches[0];
}

if (isset($matches[2])) {
$text = sprintf('%'.$matches[2], $text);
}

return $text;
}, $this->format));
$line = $this->buildLine();
$line = $this->adjustLineWidthToTerminalWidth($line);
$this->overwrite($line);
}

/**
Expand Down Expand Up @@ -592,4 +586,45 @@ private static function initFormats()
'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%',
);
}

/**
* @return string
*/
private function buildLine()
{
return preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) {
if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) {
$text = call_user_func($formatter, $this, $this->output);
} elseif (isset($this->messages[$matches[1]])) {
$text = $this->messages[$matches[1]];
} else {
return $matches[0];
}

if (isset($matches[2])) {
$text = sprintf('%'.$matches[2], $text);
}

return $text;
}, $this->format);
}

/**
* @param string $line
*
* @return bool
*/
private function adjustLineWidthToTerminalWidth($line)
{
$lineLength = Helper::strlenWithoutDecoration($this->output->getFormatter(), $line);
$terminalWidth = $this->terminalDimensionsProvider->getTerminalWidth();
if ($lineLength > $terminalWidth) {
$newBarWidth = $this->barWidth - $lineLength + $terminalWidth;
$this->setBarWidth($newBarWidth);

return $this->buildLine();
}

return $line;
}
}

0 comments on commit b030c24

Please sign in to comment.