From 260702eae8dd5a32cdc29d916d8acc409b163d48 Mon Sep 17 00:00:00 2001 From: ogizanagi Date: Sun, 24 May 2015 19:59:51 +0200 Subject: [PATCH 1/2] [Console] SymfonyStyle : Improve EOL consistency by relying on output instance --- .../Component/Console/Style/SymfonyStyle.php | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Console/Style/SymfonyStyle.php b/src/Symfony/Component/Console/Style/SymfonyStyle.php index 6d69eca54a..6f0bacd670 100644 --- a/src/Symfony/Component/Console/Style/SymfonyStyle.php +++ b/src/Symfony/Component/Console/Style/SymfonyStyle.php @@ -71,7 +71,7 @@ class SymfonyStyle extends OutputStyle // wrap and add newlines for each element foreach ($messages as $key => $message) { $message = OutputFormatter::escape($message); - $lines = array_merge($lines, explode("\n", wordwrap($message, $this->lineLength - Helper::strlen($prefix)))); + $lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - Helper::strlen($prefix), PHP_EOL))); if (count($messages) > 1 && $key < count($messages) - 1) { $lines[] = ''; @@ -92,7 +92,8 @@ class SymfonyStyle extends OutputStyle } } - $this->writeln(implode("\n", $lines)."\n"); + $this->writeln($lines); + $this->newLine(); } /** @@ -100,7 +101,12 @@ class SymfonyStyle extends OutputStyle */ public function title($message) { - $this->writeln(sprintf("\n%s\n%s\n", $message, str_repeat('=', strlen($message)))); + $this->newLine(); + $this->writeln(array( + sprintf('%s', $message), + sprintf('%s', str_repeat('=', strlen($message))), + )); + $this->newLine(); } /** @@ -108,7 +114,11 @@ class SymfonyStyle extends OutputStyle */ public function section($message) { - $this->writeln(sprintf("%s\n%s\n", $message, str_repeat('-', strlen($message)))); + $this->writeln(array( + sprintf('%s', $message), + sprintf('%s', str_repeat('-', strlen($message))), + )); + $this->newLine(); } /** @@ -122,7 +132,8 @@ class SymfonyStyle extends OutputStyle $elements ); - $this->writeln(implode("\n", $elements)."\n"); + $this->writeln($elements); + $this->newLine(); } /** From fc598ff6adda07729fefd4a17cdf07bf086dc4b2 Mon Sep 17 00:00:00 2001 From: ogizanagi Date: Mon, 11 May 2015 20:21:44 +0200 Subject: [PATCH 2/2] [Console] SymfonyStyle : fix & automate block gaps. Autoprepend appropriate blocks by the correct number of blank lines. Handle most of the SymfonyStyle guide line breaks and gaps automatically and fix thing such as double blank lines between titles. Add output tests. Fix askQuestion method, which should not output anything when the input isn't interactive. --- .../Component/Console/Style/SymfonyStyle.php | 81 +++++++++++++++++-- .../Style/SymfonyStyle/command/command_0.php | 11 +++ .../Style/SymfonyStyle/command/command_1.php | 13 +++ .../Style/SymfonyStyle/command/command_2.php | 16 ++++ .../Style/SymfonyStyle/command/command_3.php | 12 +++ .../Style/SymfonyStyle/command/command_4.php | 34 ++++++++ .../Style/SymfonyStyle/command/command_5.php | 29 +++++++ .../Style/SymfonyStyle/command/command_6.php | 16 ++++ .../Style/SymfonyStyle/command/command_7.php | 15 ++++ .../Style/SymfonyStyle/output/output_0.txt | 3 + .../Style/SymfonyStyle/output/output_1.txt | 9 +++ .../Style/SymfonyStyle/output/output_2.txt | 13 +++ .../Style/SymfonyStyle/output/output_3.txt | 7 ++ .../Style/SymfonyStyle/output/output_4.txt | 32 ++++++++ .../Style/SymfonyStyle/output/output_5.txt | 11 +++ .../Style/SymfonyStyle/output/output_6.txt | 6 ++ .../Style/SymfonyStyle/output/output_7.txt | 5 ++ .../Console/Tests/Style/SymfonyStyleTest.php | 45 +++++++++++ 18 files changed, 352 insertions(+), 6 deletions(-) create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_0.php create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_1.php create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_2.php create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_3.php create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_4.php create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_5.php create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_6.php create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_7.php create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_0.txt create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_1.txt create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_2.txt create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_3.txt create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_4.txt create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_5.txt create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_6.txt create mode 100644 src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_7.txt create mode 100644 src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php diff --git a/src/Symfony/Component/Console/Style/SymfonyStyle.php b/src/Symfony/Component/Console/Style/SymfonyStyle.php index 6f0bacd670..9ef9c08a5a 100644 --- a/src/Symfony/Component/Console/Style/SymfonyStyle.php +++ b/src/Symfony/Component/Console/Style/SymfonyStyle.php @@ -18,6 +18,7 @@ use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Helper\SymfonyQuestionHelper; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\ConfirmationQuestion; @@ -36,6 +37,7 @@ class SymfonyStyle extends OutputStyle private $questionHelper; private $progressBar; private $lineLength; + private $bufferedOutput; /** * @param InputInterface $input @@ -45,6 +47,7 @@ class SymfonyStyle extends OutputStyle { $this->input = $input; $this->lineLength = min($this->getTerminalWidth(), self::MAX_LINE_LENGTH); + $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter()); parent::__construct($output); } @@ -60,6 +63,7 @@ class SymfonyStyle extends OutputStyle */ public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false) { + $this->autoPrependBlock(); $messages = is_array($messages) ? array_values($messages) : array($messages); $lines = array(); @@ -101,7 +105,7 @@ class SymfonyStyle extends OutputStyle */ public function title($message) { - $this->newLine(); + $this->autoPrependBlock(); $this->writeln(array( sprintf('%s', $message), sprintf('%s', str_repeat('=', strlen($message))), @@ -114,6 +118,7 @@ class SymfonyStyle extends OutputStyle */ public function section($message) { + $this->autoPrependBlock(); $this->writeln(array( sprintf('%s', $message), sprintf('%s', str_repeat('-', strlen($message))), @@ -126,11 +131,10 @@ class SymfonyStyle extends OutputStyle */ public function listing(array $elements) { + $this->autoPrependText(); $elements = array_map(function ($element) { - return sprintf(' * %s', $element); - }, - $elements - ); + return sprintf(' * %s', $element); + }, $elements); $this->writeln($elements); $this->newLine(); @@ -141,6 +145,8 @@ class SymfonyStyle extends OutputStyle */ public function text($message) { + $this->autoPrependText(); + if (!is_array($message)) { $this->writeln(sprintf(' // %s', $message)); @@ -301,17 +307,51 @@ class SymfonyStyle extends OutputStyle */ public function askQuestion(Question $question) { + if ($this->input->isInteractive()) { + $this->autoPrependBlock(); + } + if (!$this->questionHelper) { $this->questionHelper = new SymfonyQuestionHelper(); } $answer = $this->questionHelper->ask($this->input, $this, $question); - $this->newLine(); + if ($this->input->isInteractive()) { + $this->newLine(); + $this->bufferedOutput->write("\n"); + } return $answer; } + /** + * {@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)); + } + /** * @return ProgressBar */ @@ -331,4 +371,33 @@ class SymfonyStyle extends OutputStyle return $dimensions[0] ?: self::MAX_LINE_LENGTH; } + + private function autoPrependBlock() + { + $chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2); + + if (false === $chars) { + 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)); + } } diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_0.php b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_0.php new file mode 100644 index 0000000000..8fe7c07712 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_0.php @@ -0,0 +1,11 @@ +caution('Lorem ipsum dolor sit amet'); +}; diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_1.php b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_1.php new file mode 100644 index 0000000000..e5c700d60e --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_1.php @@ -0,0 +1,13 @@ +title('Title'); + $output->warning('Lorem ipsum dolor sit amet'); + $output->title('Title'); +}; diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_2.php b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_2.php new file mode 100644 index 0000000000..791b626f24 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_2.php @@ -0,0 +1,16 @@ +warning('Warning'); + $output->caution('Caution'); + $output->error('Error'); + $output->success('Success'); + $output->note('Note'); + $output->block('Custom block', 'CUSTOM', 'fg=white;bg=green', 'X ', true); +}; diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_3.php b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_3.php new file mode 100644 index 0000000000..99253a6c08 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_3.php @@ -0,0 +1,12 @@ +title('First title'); + $output->title('Second title'); +}; diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_4.php b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_4.php new file mode 100644 index 0000000000..0c5d3fb26c --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_4.php @@ -0,0 +1,34 @@ +write('Lorem ipsum dolor sit amet'); + $output->title('First title'); + + $output->writeln('Lorem ipsum dolor sit amet'); + $output->title('Second title'); + + $output->write('Lorem ipsum dolor sit amet'); + $output->write(''); + $output->title('Third title'); + + //Ensure edge case by appending empty strings to history: + $output->write('Lorem ipsum dolor sit amet'); + $output->write(array('', '', '')); + $output->title('Fourth title'); + + //Ensure have manual control over number of blank lines: + $output->writeln('Lorem ipsum dolor sit amet'); + $output->writeln(array('', '')); //Should append an extra blank line + $output->title('Fifth title'); + + $output->writeln('Lorem ipsum dolor sit amet'); + $output->newLine(2); //Should append an extra blank line + $output->title('Fifth title'); +}; diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_5.php b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_5.php new file mode 100644 index 0000000000..4543ad8cd6 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_5.php @@ -0,0 +1,29 @@ +writeln('Lorem ipsum dolor sit amet'); + $output->listing(array( + 'Lorem ipsum dolor sit amet', + 'consectetur adipiscing elit', + )); + + //Even using write: + $output->write('Lorem ipsum dolor sit amet'); + $output->listing(array( + 'Lorem ipsum dolor sit amet', + 'consectetur adipiscing elit', + )); + + $output->write('Lorem ipsum dolor sit amet'); + $output->text(array( + 'Lorem ipsum dolor sit amet', + 'consectetur adipiscing elit', + )); +}; diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_6.php b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_6.php new file mode 100644 index 0000000000..8031ec9c30 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_6.php @@ -0,0 +1,16 @@ +listing(array( + 'Lorem ipsum dolor sit amet', + 'consectetur adipiscing elit', + )); + $output->success('Lorem ipsum dolor sit amet'); +}; diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_7.php b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_7.php new file mode 100644 index 0000000000..203eb5b12e --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_7.php @@ -0,0 +1,15 @@ +title('Title'); + $output->askHidden('Hidden question'); + $output->choice('Choice question with default', array('choice1', 'choice2'), 'choice1'); + $output->confirm('Confirmation with yes default', true); + $output->text('Duis aute irure dolor in reprehenderit in voluptate velit esse'); +}; diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_0.txt b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_0.txt new file mode 100644 index 0000000000..a42e0f792a --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_0.txt @@ -0,0 +1,3 @@ + + ! [CAUTION] Lorem ipsum dolor sit amet + diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_1.txt b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_1.txt new file mode 100644 index 0000000000..334875f789 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_1.txt @@ -0,0 +1,9 @@ + +Title +===== + + [WARNING] Lorem ipsum dolor sit amet + +Title +===== + diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_2.txt b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_2.txt new file mode 100644 index 0000000000..ca609760cc --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_2.txt @@ -0,0 +1,13 @@ + + [WARNING] Warning + + ! [CAUTION] Caution + + [ERROR] Error + + [OK] Success + + ! [NOTE] Note + +X [CUSTOM] Custom block + diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_3.txt b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_3.txt new file mode 100644 index 0000000000..f4b6d58276 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_3.txt @@ -0,0 +1,7 @@ + +First title +=========== + +Second title +============ + diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_4.txt b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_4.txt new file mode 100644 index 0000000000..2646d858e7 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_4.txt @@ -0,0 +1,32 @@ +Lorem ipsum dolor sit amet + +First title +=========== + +Lorem ipsum dolor sit amet + +Second title +============ + +Lorem ipsum dolor sit amet + +Third title +=========== + +Lorem ipsum dolor sit amet + +Fourth title +============ + +Lorem ipsum dolor sit amet + + +Fifth title +=========== + +Lorem ipsum dolor sit amet + + +Fifth title +=========== + diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_5.txt b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_5.txt new file mode 100644 index 0000000000..910240fbfd --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_5.txt @@ -0,0 +1,11 @@ +Lorem ipsum dolor sit amet + * Lorem ipsum dolor sit amet + * consectetur adipiscing elit + +Lorem ipsum dolor sit amet + * Lorem ipsum dolor sit amet + * consectetur adipiscing elit + +Lorem ipsum dolor sit amet + // Lorem ipsum dolor sit amet + // consectetur adipiscing elit diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_6.txt b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_6.txt new file mode 100644 index 0000000000..5f2d33c148 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_6.txt @@ -0,0 +1,6 @@ + + * Lorem ipsum dolor sit amet + * consectetur adipiscing elit + + [OK] Lorem ipsum dolor sit amet + diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_7.txt b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_7.txt new file mode 100644 index 0000000000..ab18e5dc76 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_7.txt @@ -0,0 +1,5 @@ + +Title +===== + + // Duis aute irure dolor in reprehenderit in voluptate velit esse diff --git a/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php b/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php new file mode 100644 index 0000000000..cad1f16c8a --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php @@ -0,0 +1,45 @@ +command = new Command('sfstyle'); + $this->tester = new CommandTester($this->command); + } + + protected function tearDown() + { + $this->command = null; + $this->tester = null; + } + + /** + * @dataProvider inputCommandToOutputFilesProvider + */ + public function testOutputs($inputCommandFilepath, $outputFilepath) + { + $code = require $inputCommandFilepath; + $this->command->setCode($code); + $this->tester->execute(array(), array('interactive' => false, 'decorated' => false)); + $this->assertStringEqualsFile($outputFilepath, $this->tester->getDisplay(true)); + } + + public function inputCommandToOutputFilesProvider() + { + $baseDir = __DIR__.'/../Fixtures/Style/SymfonyStyle'; + + return array_map(null, glob($baseDir.'/command/command_*.php'), glob($baseDir.'/output/output_*.txt')); + } +}