8000 bug #14623 [Console] SymfonyStyle : fix & automate block gaps. (ogiza… · symfony/symfony@c62069b · GitHub
[go: up one dir, main page]

Skip to content

Commit c62069b

Browse files
committed
bug #14623 [Console] SymfonyStyle : fix & automate block gaps. (ogizanagi)
This PR was merged into the 2.7 branch. Discussion ---------- [Console] SymfonyStyle : fix & automate block gaps. | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - --- Depends on #14741 --- ## What it does - autoprepend appropriate blocks (like cautions, titles, sections, ...) by the correct number of blank lines considering history. - handle automatically most of the SymfonyStyle guide line breaks and gaps. Fix things such as unwanted double blank lines between titles and admonitions. - test outputs - fix an issue using questions with SymfonyStyle, which should not output extra blank lines when using with a non-interactive input. ## Description `SymfonyStyle` is great, but there are some issues, mostly when using blocks (text blocks, titles and admonitions): some extra blank lines might be generated. Plus, on the contrary, some line breaks or blank lines around blocks are missing, and the developer need to handle this himself by polluting his code with ugly `if` and `newLine()` statements. ### Before / After : ![screenshot 2015-05-13 a 00 11 59](https://cloud.githubusercontent.com/assets/2211145/7600572/ccfa8904-f90c-11e4-999f-d89612360424.PNG) As you can see, it's still up to the developper to end his command by a blank line (unless using a block like `SymfonyStyle::success()`) in order to distinct different commands outputs more efficiently. Everything else is now handled properly, and automatically, according to the rules exposed in the symfony console style guide published some time ago by @javiereguiluz . Questions (not exposed in the above output) are considered as blocks, and follow, for instance, the same conditions than admonitions: 1 blank line before and after, no more (although, you'll still be able to output more blank lines yourself, using `newLine`). Commits ------- fc598ff [Console] SymfonyStyle : fix & automate block gaps. 260702e [Console] SymfonyStyle : Improve EOL consistency by relying on output instance
2 parents 807d192 + fc598ff commit c62069b

File tree

18 files changed

+367
-10
lines changed
  • output
  • Style
  • 18 files changed

    +367
    -10
    lines changed

    src/Symfony/Component/Console/Style/SymfonyStyle.php

    Lines changed: 90 additions & 10 deletions
    Original file line numberDiff line numberDiff line change
    @@ -18,6 +18,7 @@
    1818
    use Symfony\Component\Console\Helper\SymfonyQuestionHelper;
    1919
    use Symfony\Component\Console\Helper\Table;
    2020
    use Symfony\Component\Console\Input\InputInterface;
    21+
    use Symfony\Component\Console\Output\BufferedOutput;
    2122
    use Symfony\Component\Console\Output\OutputInterface;
    2223
    use Symfony\Component\Console\Question\ChoiceQuestion;
    2324
    use Symfony\Component\Console\Question\ConfirmationQuestion;
    @@ -36,6 +37,7 @@ class SymfonyStyle extends OutputStyle
    3637
    private $questionHelper;
    3738
    private $progressBar;
    3839
    private $lineLength;
    40+
    private $bufferedOutput;
    3941

    4042
    /**
    4143
    * @param InputInterface $input
    @@ -45,6 +47,7 @@ public function __construct(InputInterface $input, OutputInterface $output)
    4547
    {
    4648
    $this->input = $input;
    4749
    $this->lineLength = min($this->getTerminalWidth(), self::MAX_LINE_LENGTH);
    50+
    $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter());
    4851

    4952
    parent::__construct($output);
    5053
    }
    @@ -60,6 +63,7 @@ public function __construct(InputInterface $input, OutputInterface $output)
    6063
    */
    6164
    public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false)
    6265
    {
    66+
    $this->autoPrependBlock();
    6367
    $messages = is_array($messages) ? array_values($messages) : array($messages);
    6468
    $lines = array();
    6569

    @@ -71,7 +75,7 @@ public function block($messages, $type = null, $style = null, $prefix = ' ', $pa
    7175
    // wrap and add newlines for each element
    7276
    foreach ($messages as $key => $message) {
    7377
    $message = OutputFormatter::escape($message);
    74-
    $lines = array_merge($lines, explode("\n", wordwrap($message, $this->lineLength - Helper::strlen($prefix))));
    78+
    $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - Helper::strlen($prefix), PHP_EOL)));
    7579

    7680
    if (count($messages) > 1 && $key < count($messages) - 1) {
    7781
    $lines[] = '';
    @@ -92,44 +96,57 @@ public function block($messages, $type = null, $style = null, $prefix = ' ', $pa
    9296
    }
    9397
    }
    9498

    95-
    $this->writeln(implode("\n", $lines)."\n");
    99+
    $this->writeln($lines);
    100+
    $this->newLine();
    96101
    }
    97102

    98103
    /**
    99104
    * {@inheritdoc}
    100105
    */
    101106
    public function title($message)
    102107
    {
    103-
    $this->writeln(sprintf("\n<comment>%s</>\n<comment>%s</>\n", $message, str_repeat('=', strlen($message))));
    108+
    $this->autoPrependBlock();
    109+
    $this->writeln(array(
    110+
    sprintf('<comment>%s</>', $message),
    111+
    sprintf('<comment>%s</>', str_repeat('=', strlen($message))),
    112+
    ));
    113+
    $this->newLine();
    104114
    }
    105115

    106116
    /**
    107117
    * {@inheritdoc}
    108118
    */
    109119
    public function section($message)
    110120
    {
    111-
    $this->writeln(sprintf("<comment>%s</>\n<comment>%s</>\n", $message, str_repeat('-', strlen($message))));
    121+
    $this->autoPrependBlock();
    122+
    $this->writeln(array(
    123+
    sprintf('<comment>%s</>', $message),
    124+
    sprintf('<comment>%s</>', str_repeat('-', strlen($message))),
    125+
    ));
    126+
    $this->newLine();
    112127
    }
    113128

    114129
    /**
    115130
    * {@inheritdoc}
    116131
    */
    117132
    public function listing(array $elements)
    118133
    {
    134+
    $this->autoPrependText();
    119135
    $elements = array_map(function ($element) {
    120-
    return sprintf(' * %s', $element);
    121-
    },
    122-
    $elements
    123-
    );
    136+
    return sprintf(' * %s', $element);
    137+
    }, $elements);
    124138

    125-
    $this->writeln(implode("\n", $elements)."\n");
    139+
    $this->writeln($elements);
    140+
    $this->newLine();
    126141
    }
    127142

    128143
    /**
    129144
    * {@inheritdoc}
    130145
    */
    131146
    public function text($message)
    132147
    {
    148+
    $this->autoPrependText();
    149+
    133150
    if (!is_array($message)) {
    134151
    $this->writeln(sprintf(' // %s', $message));
    135152

    @@ -292,17 +309,51 @@ public function createProgressBar($max = 0)
    292309
    */
    293310
    public function askQuestion(Question $question)
    294311
    {
    312+
    if ($this->input->isInteractive()) {
    313+
    $this->autoPrependBlock();
    314+
    }
    315+
    295316
    if (!$this->questionHelper) {
    296317
    $this->questionHelper = new SymfonyQuestionHelper();
    297318
    }
    298319

    299320
    $answer = $this->questionHelper->ask($this->input, $this, $question);
    300321

    301-
    $this->newLine();
    322+
    if ($this->input->isInteractive()) {
    323+
    $this->newLine();
    324+
    $this->bufferedOutput->write("\n");
    325+
    }
    302326

    303327
    return $answer;
    304328
    }
    305329

    330+
    /**
    331+
    * {@inheritdoc}
    332+
    */
    333+
    public function writeln($messages, $type = self::OUTPUT_NORMAL)
    334+
    {
    335+
    parent::writeln($messages, $type);
    336+
    $this->bufferedOutput->writeln($this->reduceBuffer($messages), $type);
    337+
    }
    338+
    339+
    /**
    340+
    * {@inheritdoc}
    341+
    */
    342+
    public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
    343+
    {
    344+
    parent::write($messages, $newline, $type);
    345+
    $this->bufferedOutput->write($this->reduceBuffer($messages), $newline, $type);
    346+
    }
    347+
    348+
    /**
    349+
    * {@inheritdoc}
    350+
    */
    351+
    public function newLine($count = 1)
    352+
    {
    353+
    parent::newLine($count);
    354+
    $this->bufferedOutput->write(str_repeat("\n", $count));
    355+
    }
    356+
    306357
    /**
    307358
    * @return ProgressBar
    308359
    */
    @@ -322,4 +373,33 @@ private function getTerminalWidth()
    322373

    323374
    return $dimensions[0] ?: self::MAX_LINE_LENGTH;
    324375
    }
    376+
    377+
    private function autoPrependBlock()
    378+
    {
    379+
    $chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);
    380+
    381+
    if (false === $chars) {
    382+
    return $this->newLine(); //empty history, so we should start with a new line.
    383+
    }
    384+
    //Prepend new line for each non LF chars (This means no blank line was output before)
    385+
    $this->newLine(2 - substr_count($chars, "\n"));
    386+
    }
    387+
    388+
    private function autoPrependText()
    389+
    {
    390+
    $fetched = $this->bufferedOutput->fetch();
    391+
    //Prepend new line if last char isn't EOL:
    392+
    if ("\n" !== substr($fetched, -1)) {
    393+
    $this->newLine();
    394+
    }
    395+
    }
    396+
    397+
    private function reduceBuffer($messages)
    398+
    {
    399+
    // We need to know if the two last chars are PHP_EOL
    400+
    // Preserve the last 4 chars inserted (PHP_EOL on windows is two chars) in the history buffer
    401+
    return array_map(function ($value) {
    402+
    return substr($value, -4);
    403+
    }, array_merge(array($this->bufferedOutput->fetch()), (array) $messages));
    404+
    }
    325405
    }
    Lines changed: 11 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,11 @@
    1+
    <?php
    2+
    3+
    use Symfony\Component\Console\Input\InputInterface;
    4+
    use Symfony\Component\Console\Output\OutputInterface;
    5+
    use Symfony\Component\Console\Style\SymfonyStyle;
    6+
    7+
    //Ensure has single blank line at start when using block element
    8+
    return function (InputInterface $input, OutputInterface $output) {
    9+
    $output = new SymfonyStyle($input, $output);
    10+
    $output->caution('Lorem ipsum dolor sit amet');
    11+
    };
    Lines changed: 13 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,13 @@
    1+
    <?php
    2+
    3+
    use Symfony\Component\Console\Input\InputInterface;
    4+
    use Symfony\Component\Console\Output\OutputInterface;
    5+
    use Symfony\Component\Console\Style\SymfonyStyle;
    6+
    7+
    //Ensure has single blank line between titles and blocks
    8+
    return function (InputInterface $input, OutputInterface $output) {
    9+
    $output = new SymfonyStyle($input, $output);
    10+
    $output->title('Title');
    11+
    $output->warning('Lorem ipsum dolor sit amet');
    12+
    $output->title('Title');
    13+
    };
    Lines changed: 16 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,16 @@
    1+
    <?php
    2+
    3+
    use Symfony\Component\Console\Input\InputInterface;
    4+
    use Symfony\Component\Console\Output\OutputInterface;
    5+
    use Symfony\Component\Console\Style\SymfonyStyle;
    6+
    7+
    //Ensure has single blank line between blocks
    8+
    return function (InputInterface $input, OutputInterface $output) {
    9+
    $output = new SymfonyStyle($input, $output);
    10+
    $output->warning('Warning');
    11+
    $output->caution('Caution');
    12+
    $output->error('Error');
    13+
    $output->success('Success');
    14+
    $output->note('Note');
    15+
    $output->block('Custom block', 'CUSTOM', 'fg=white;bg=green', 'X ', true);
    16+
    };
    Lines changed: 12 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,12 @@
    1+
    <?php
    2+
    3+
    use Symfony\Component\Console\Input\InputInterface;
    4+
    use Symfony\Component\Console\Output\OutputInterface;
    5+
    use Symfony\Component\Console\Style\SymfonyStyle;
    6+
    7+
    //Ensure has single blank line between two titles
    8+
    return function (InputInterface $input, OutputInterface $output) {
    9+
    $output = new SymfonyStyle($input, $output);
    10+
    $output->title('First title');
    11+
    $output->title('Second title');
    12+
    };
    Lines changed: 34 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,34 @@
    1+
    <?php
    2+
    3+
    use Symfony\Component\Console\Input\InputInterface;
    4+
    use Symfony\Component\Console\Output\OutputInterface;
    5+
    use Symfony\Component\Console\Style\SymfonyStyle;
    6+
    7+
    //Ensure has single blank line after any text and a title
    8+
    return function (InputInterface $input, OutputInterface $output) {
    9+
    $output = new SymfonyStyle($input, $output);
    10+
    11+
    $output->write('Lorem ipsum dolor sit amet');
    12+
    $output->title('First title');
    13+
    14+
    $output->writeln('Lorem ipsum dolor sit amet');
    15+
    $output->title('Second title');
    16+
    17+
    $output->write('Lorem ipsum dolor sit amet');
    18+
    $output->write('');
    19+
    $output->title('Third title');
    20+
    21+
    //Ensure edge case by appending empty strings to history:
    22+
    $output->write('Lorem ipsum dolor sit amet');
    23+
    $output->write(array('', '', ''));
    24+
    $output->title('Fourth title');
    25+
    26+
    //Ensure have manual control over number of blank lines:
    27+
    $output->writeln('Lorem ipsum dolor sit amet');
    28+
    $output->writeln(array('', '')); //Should append an extra blank line
    29+
    $output->title('Fifth title');
    30+
    31+
    $output->writeln('Lorem ipsum dolor sit amet');
    32+
    $output->newLine(2); //Should append an extra blank line
    33+
    $output->title('Fifth title');
    34+
    };
    Lines changed: 29 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,29 @@
    1+
    <?php
    2+
    3+
    use Symfony\Component\Console\Input\InputInterface;
    4+
    use Symfony\Component\Console\Output\OutputInterface;
    5+
    use Symfony\Component\Console\Style\SymfonyStyle;
    6+
    7+
    //Ensure has proper line ending before outputing a text block like with SymfonyStyle::listing() or SymfonyStyle::text()
    8+
    return function (InputInterface $input, OutputInterface $output) {
    9+
    $output = new SymfonyStyle($input, $output);
    10+
    11+
    $output->writeln('Lorem ipsum dolor sit amet');
    12+
    $output->listing(array(
    13+
    'Lorem ipsum dolor sit amet',
    14+
    'consectetur adipiscing elit',
    15+
    ));
    16+
    17+
    //Even using write:
    18+
    $output->write('Lorem ipsum dolor sit amet');
    19+
    $output->listing(array(
    20+
    'Lorem ipsum dolor sit amet',
    21+
    'consectetur adipiscing elit',
    22+
    ));
    23+
    24+
    $output->write('Lorem ipsum dolor sit amet');
    25+
    $output->text(array(
    26+
    'Lorem ipsum dolor sit amet',
    27+
    'consectetur adipiscing elit',
    28+
    ));
    29+
    };
    Lines changed: 16 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,16 @@
    1+
    <?php
    2+
    3+
    use Symfony\Component\Console\Input\InputInterface;
    4+
    use Symfony\Component\Console\Output\OutputInterface;
    5+
    use Symfony\Component\Console\Style\SymfonyStyle;
    6+
    7+
    //Ensure has proper blank line after text block when using a block like with SymfonyStyle::success
    8+
    return function (InputInterface $input, OutputInterface $output) {
    9+
    $output = new SymfonyStyle($input, $output);
    10+
    11+
    $output->listing(array(
    12+
    'Lorem ipsum dolor sit amet',
    13+
    'consectetur adipiscing elit',
    14+
    ));
    15+
    $output->success('Lorem ipsum dolor sit amet');
    16+
    };
    Lines changed: 15 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,15 @@
    1+
    <?php
    2+
    3+
    use Symfony\Component\Console\Input\InputInterface;
    4+
    use Symfony\Component\Console\Output\OutputInterface;
    5+
    use Symfony\Component\Console\Style\SymfonyStyle;
    6+
    7+
    //Ensure questions do not output anything when input is non-interactive
    8+
    return function (InputInterface $input, OutputInterface $output) {
    9+
    $output = new SymfonyStyle($input, $output);
    10+
    $output->title('Title');
    11+
    $output->askHidden('Hidden question');
    12+
    $output->choice('Choice question with default', array('choice1', 'choice2'), 'choice1');
    13+
    $output->confirm('Confirmation with yes default', true);
    14+
    $output->text('Duis aute irure dolor in reprehenderit in voluptate velit esse');
    15+
    };
    Lines changed: 3 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,3 @@
    1+
    2+
    ! [CAUTION] Lorem ipsum dolor sit amet
    3+
    Lines changed: 9 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,9 @@
    1+
    2+
    Title
    3+
    =====
    4+
    5+
    [WARNING] Lorem ipsum dolor sit amet
    6+
    7+
    Title
    8+
    =====
    9+
    Lines changed: 13 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,13 @@
    1+
    2+
    [WARNING] Warning
    3+
    4+
    ! [CAUTION] Caution
    5+
    6+
    [ERROR] Error
    7+
    8+
    [OK] Success
    9+
    10+
    ! [NOTE] Note
    11+
    12+
    X [CUSTOM] Custom block
    13+
    Lines changed: 7 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,7 @@
    1+
    2+
    First title
    3+
    ===========
    4+
    5+
    Second title
    6+
    ============
    7+

    0 commit comments

    Comments
     (0)
    0