Skip to content

Commit

Permalink
[RFC][Console] Added console style guide helpers (v2)
Browse files Browse the repository at this point in the history
  • Loading branch information
kbond authored and fabpot committed Mar 30, 2015
1 parent de303b3 commit 104104c
Show file tree
Hide file tree
Showing 6 changed files with 747 additions and 24 deletions.
71 changes: 47 additions & 24 deletions Helper/QuestionHelper.php
Expand Up @@ -109,25 +109,11 @@ public function getName()
*/
public function doAsk(OutputInterface $output, Question $question)
{
$inputStream = $this->inputStream ?: STDIN;

$message = $question->getQuestion();
if ($question instanceof ChoiceQuestion) {
$width = max(array_map('strlen', array_keys($question->getChoices())));

$messages = (array) $question->getQuestion();
foreach ($question->getChoices() as $key => $value) {
$messages[] = sprintf(" [<info>%-${width}s</info>] %s", $key, $value);
}

$output->writeln($messages);

$message = $question->getPrompt();
}

$output->write($message);
$this->writePrompt($output, $question);

$inputStream = $this->inputStream ?: STDIN;
$autocomplete = $question->getAutocompleterValues();

if (null === $autocomplete || !$this->hasSttyAvailable()) {
$ret = false;
if ($question->isHidden()) {
Expand Down Expand Up @@ -160,6 +146,49 @@ public function doAsk(OutputInterface $output, Question $question)
return $ret;
}

/**
* Outputs the question prompt.
*
* @param OutputInterface $output
* @param Question $question
*/
protected function writePrompt(OutputInterface $output, Question $question)
{
$message = $question->getQuestion();

if ($question instanceof ChoiceQuestion) {
$width = max(array_map('strlen', array_keys($question->getChoices())));

$messages = (array) $question->getQuestion();
foreach ($question->getChoices() as $key => $value) {
$messages[] = sprintf(" [<info>%-${width}s</info>] %s", $key, $value);
}

$output->writeln($messages);

$message = $question->getPrompt();
}

$output->write($message);
}

/**
* Outputs an error message.
*
* @param OutputInterface $output
* @param \Exception $error
*/
protected function writeError(OutputInterface $output, \Exception $error)
{
if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) {
$message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error');
} else {
$message = '<error>'.$error->getMessage().'</error>';
}

$output->writeln($message);
}

/**
* Autocompletes a question.
*
Expand Down Expand Up @@ -355,13 +384,7 @@ private function validateAttempts($interviewer, OutputInterface $output, Questio
$attempts = $question->getMaxAttempts();
while (null === $attempts || $attempts--) {
if (null !== $error) {
if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) {
$message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error');
} else {
$message = '<error>'.$error->getMessage().'</error>';
}

$output->writeln($message);
$this->writeError($output, $error);
}

try {
Expand Down
106 changes: 106 additions & 0 deletions Helper/SymfonyQuestionHelper.php
@@ -0,0 +1,106 @@
<?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\Helper;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
* Symfony Style Guide compliant question helper.
*
* @author Kevin Bond <kevinbond@gmail.com>
*/
class SymfonyQuestionHelper extends QuestionHelper
{
/**
* {@inheritdoc}
*/
public function ask(InputInterface $input, OutputInterface $output, Question $question)
{
$validator = $question->getValidator();
$question->setValidator(function ($value) use ($validator) {
if (null !== $validator && is_callable($validator)) {
$value = $validator($value);
}

// make required
if (!is_array($value) && !is_bool($value) && 0 === strlen($value)) {
throw new \Exception('A value is required.');
}

return $value;
});

return parent::ask($input, $output, $question);
}

/**
* {@inheritdoc}
*/
protected function writePrompt(OutputInterface $output, Question $question)
{
$text = $question->getQuestion();
$default = $question->getDefault();

switch (true) {
case null === $default:
$text = sprintf(' <info>%s</info>:', $text);

break;

case $question instanceof ConfirmationQuestion:
$text = sprintf(' <info>%s (yes/no)</info> [<comment>%s</comment>]:', $text, $default ? 'yes' : 'no');

break;

case $question instanceof ChoiceQuestion:
$choices = $question->getChoices();
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, $choices[$default]);

break;

default:
$text = sprintf(' <info>%s</info> [<comment>%s</comment>]:', $text, $default);
}

$output->writeln($text);

if ($question instanceof ChoiceQuestion) {
$width = max(array_map('strlen', array_keys($question->getChoices())));

foreach ($question->getChoices() as $key => $value) {
$output->writeln(sprintf(" [<comment>%-${width}s</comment>] %s", $key, $value));
}
}

$output->write(' > ');
}

/**
* {@inheritdoc}
*/
protected function writeError(OutputInterface $output, \Exception $error)
{
if ($output instanceof SymfonyStyle) {
$output->newLine();
$output->error($error->getMessage());

return;
}

parent::writeError($output, $error);
}
}
9 changes: 9 additions & 0 deletions Helper/Table.php
Expand Up @@ -401,10 +401,19 @@ private static function initStyles()
->setCellRowContentFormat('%s')
;

$styleGuide = new TableStyle();
$styleGuide
->setHorizontalBorderChar('-')
->setVerticalBorderChar(' ')
->setCrossingChar(' ')
->setCellHeaderFormat('%s')
;

return array(
'default' => new TableStyle(),
'borderless' => $borderless,
'compact' => $compact,
'symfony-style-guide' => $styleGuide,
);
}
}
116 changes: 116 additions & 0 deletions Style/OutputStyle.php
@@ -0,0 +1,116 @@
<?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\Formatter\OutputFormatterInterface;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Decorates output to add console style guide helpers
*
* @author Kevin Bond <kevinbond@gmail.com>
*/
abstract class OutputStyle implements OutputInterface, StyleInterface
{
private $output;

/**
* @param OutputInterface $output
*/
public function __construct(OutputInterface $output)
{
$this->output = $output;
}

/**
* {@inheritdoc}
*/
public function newLine($count = 1)
{
$this->output->write(str_repeat(PHP_EOL, $count));
}

/**
* @param int $max
*
* @return ProgressBar
*/
public function createProgressBar($max = 0)
{
return new ProgressBar($this->output, $max);
}

/**
* {@inheritdoc}
*/
public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
{
$this->output->write($messages, $newline, $type);
}

/**
* {@inheritdoc}
*/
public function writeln($messages, $type = self::OUTPUT_NORMAL)
{
$this->output->writeln($messages, $type);
}

/**
* {@inheritdoc}
*/
public function setVerbosity($level)
{
$this->output->setVerbosity($level);
}

/**
* {@inheritdoc}
*/
public function getVerbosity()
{
return $this->output->getVerbosity();
}

/**
* {@inheritdoc}
*/
public function setDecorated($decorated)
{
$this->output->setDecorated($decorated);
}

/**
* {@inheritdoc}
*/
public function isDecorated()
{
return $this->output->isDecorated();
}

/**
* {@inheritdoc}
*/
public function setFormatter(OutputFormatterInterface $formatter)
{
$this->output->setFormatter($formatter);
}

/**
* {@inheritdoc}
*/
public function getFormatter()
{
return $this->output->getFormatter();
}
}

0 comments on commit 104104c

Please sign in to comment.