Deleting lines of the terminal using a Symfony command
Published on 2021-08-01 • Modified on 2021-08-01
In this snippet, we see how to delete lines of the terminal using a Symfony command. Symfony 5.1 has introduced a significant change that allows having complete control of the cursor in the terminal thanks to the Symfony\Component\Console\Cursor
object. Before this, we could use sections that provide a clear function. We can even do it manually using custom code like the clear()
function below.
<?php
declare(strict_types=1);
// src/Command/DeleteLinesDemoCommand.php
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Cursor;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(
name: self::NAME,
description: self::DESCRIPTION,
)]
final class DeleteLinesDemoCommand extends BaseCommand
{
public const string CMD = 'delete-lines-demo';
private const string NAME = self::NAMESPACE.':'.self::CMD;
private const string DESCRIPTION = 'Demo on how to delete lines of the terminal.';
protected function configure(): void
{
[$desc, $class] = [self::NAME, self::class];
$this->setHelp(
<<<EOT
$desc
COMMAND:
<comment>$class</comment>
DEV:
<info>%command.full_name% -vv</info>
PROD:
<info>%command.full_name% --env=prod --no-debug</info>
EOT
);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$io->write('$output: '.get_debug_type($output));
if ($output instanceof ConsoleOutputInterface) {
// @codeCoverageIgnoreStart
$section = $output->section();
$section->write('Dummy section I will clear at next line');
$section->clear();
// @codeCoverageIgnoreEnd
}
$io->write('delete me!');
$cursor = new Cursor($output);
$cursor->clearLine();
$cursor->moveLeft(10);
$io->write('delete me 2!');
$cursor->clearLine();
$io->writeln('delete me 3!');
$this->clear($output);
$io->writeln('delete me 4!');
$io->writeln('delete me 5!');
$this->clear($output, 2);
$io->success('Done!');
return self::SUCCESS;
}
/**
* @see ConsoleSectionOutput::popStreamContentUntilCurrentSection
*/
private function clear(OutputInterface $output, int $lines = 1): void
{
// move cursor up n lines
$output->write("\x1b[{$lines}A");
// erase to end of screen
$output->writeln("\x1b[0J");
}
}
≪ this.showUnitTest ? this.trans.hide_unit_test : this.trans.show_unit_test ≫ More on Stackoverflow Read the doc More on the web Random snippet
<?php
declare(strict_types=1);
namespace App\Tests\Integration\Controller\Snippets;
use App\Command\BaseCommand;
use App\Command\DeleteLinesDemoCommand;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Console\Tester\CommandTester;
final class Snippet157Test extends KernelTestCase
{
/**
* @see DeleteLinesDemoCommand::execute
*/
public function testSnippet157(): void
{
$app = new Application(self::createKernel());
$command = $app->find(BaseCommand::NAMESPACE.':'.DeleteLinesDemoCommand::CMD);
$commandTester = new CommandTester($command);
$commandTester->execute([
'command' => $command->getName(),
]);
self::assertStringContainsString('delete', $commandTester->getDisplay(), 'delete');
// 🤔 can seem weird but yes the delete string is found, it is not displayed
// because of the ANSI output.
// Here is the real content of the output (you must log it in a file)
/*
delete me![2K[10Ddelete me 2![2Kdelete me 3!
[1A[0J
delete me 4!
delete me 5!
[2A[0J
[OK] Done!
*/
}
}